[PATCH ath12k-ng 02/12] wifi: ath12k: Move monitor status processing to Wi-Fi 7 module
Alok Singh
quic_aloksing at quicinc.com
Mon Nov 10 02:37:03 PST 2025
Split Wi-Fi 7-specific monitor status processing out of ath12k common
code and into the Wi-Fi 7 module to improve modularity.
Move the following functions to wifi7/dp_mon.c and rename them with the
ath12k_wifi7_ prefix:
- ath12k_dp_mon_rx_parse_mon_status()
- ath12k_dp_rx_reap_mon_status_ring()
- ath12k_dp_mon_parse_rx_dest()
- ath12k_dp_rx_mon_buf_done()
- ath12k_dp_rx_mon_dest_process()
- ath12k_dp_mon_rx_memset_ppdu_info()
Export helper functions required by the Wi-Fi 7 monitor path.
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 | 409 +-----------------
drivers/net/wireless/ath/ath12k/dp_mon.h | 38 +-
drivers/net/wireless/ath/ath12k/hal.c | 2 +
.../net/wireless/ath/ath12k/wifi7/dp_mon.c | 399 ++++++++++++++++-
4 files changed, 433 insertions(+), 415 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c
index 5e2bf24d6b7e..37a5d46b1ca4 100644
--- a/drivers/net/wireless/ath/ath12k/dp_mon.c
+++ b/drivers/net/wireless/ath/ath12k/dp_mon.c
@@ -1461,7 +1461,7 @@ ath12k_dp_mon_parse_status_msdu_end(struct ath12k_mon_data *pmon,
RX_MSDU_END_INFO11_DECAP_FORMAT);
}
-static enum hal_rx_mon_status
+enum hal_rx_mon_status
ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_pdev_dp *dp_pdev,
struct ath12k_mon_data *pmon,
const struct hal_tlv_64_hdr *tlv)
@@ -1733,6 +1733,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_pdev_dp *dp_pdev,
return HAL_RX_MON_STATUS_PPDU_NOT_DONE;
}
+EXPORT_SYMBOL(ath12k_dp_mon_rx_parse_status_tlv);
static void
ath12k_dp_mon_fill_rx_stats_info(struct hal_rx_mon_ppdu_info *ppdu_info,
@@ -1761,7 +1762,7 @@ ath12k_dp_mon_fill_rx_stats_info(struct hal_rx_mon_ppdu_info *ppdu_info,
}
}
-static struct sk_buff
+struct sk_buff
*ath12k_dp_rx_alloc_mon_status_buf(struct ath12k_base *ab,
struct dp_rxdma_mon_ring *rx_ring,
int *buf_id)
@@ -1804,46 +1805,7 @@ static struct sk_buff
fail_alloc_skb:
return NULL;
}
-
-static enum dp_mon_status_buf_state
-ath12k_dp_rx_mon_buf_done(struct ath12k_base *ab, struct hal_srng *srng,
- struct dp_rxdma_mon_ring *rx_ring)
-{
- struct ath12k_skb_rxcb *rxcb;
- struct hal_tlv_64_hdr *tlv;
- struct sk_buff *skb;
- void *status_desc;
- dma_addr_t paddr;
- u32 cookie;
- int buf_id;
- u8 rbm;
-
- status_desc = ath12k_hal_srng_src_next_peek(ab, srng);
- if (!status_desc)
- return DP_MON_STATUS_NO_DMA;
-
- ath12k_hal_rx_buf_addr_info_get(&ab->hal, status_desc, &paddr, &cookie, &rbm);
-
- buf_id = u32_get_bits(cookie, DP_RXDMA_BUF_COOKIE_BUF_ID);
-
- spin_lock_bh(&rx_ring->idr_lock);
- skb = idr_find(&rx_ring->bufs_idr, buf_id);
- spin_unlock_bh(&rx_ring->idr_lock);
-
- if (!skb)
- return DP_MON_STATUS_NO_DMA;
-
- rxcb = ATH12K_SKB_RXCB(skb);
- dma_sync_single_for_cpu(ab->dev, rxcb->paddr,
- skb->len + skb_tailroom(skb),
- DMA_FROM_DEVICE);
-
- tlv = (struct hal_tlv_64_hdr *)skb->data;
- if (le64_get_bits(tlv->tl, HAL_TLV_HDR_TAG) != HAL_RX_STATUS_BUFFER_DONE)
- return DP_MON_STATUS_NO_DMA;
-
- return DP_MON_STATUS_REPLINISH;
-}
+EXPORT_SYMBOL(ath12k_dp_rx_alloc_mon_status_buf);
static u32 ath12k_dp_mon_comp_ppduid(u32 msdu_ppdu_id, u32 *ppdu_id)
{
@@ -2358,10 +2320,10 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev,
ieee80211_rx_napi(ath12k_pdev_dp_to_hw(dp_pdev), pubsta, msdu, napi);
}
-static int ath12k_dp_mon_rx_deliver(struct ath12k_pdev_dp *dp_pdev,
- struct dp_mon_mpdu *mon_mpdu,
- struct hal_rx_mon_ppdu_info *ppduinfo,
- struct napi_struct *napi)
+int ath12k_dp_mon_rx_deliver(struct ath12k_pdev_dp *dp_pdev,
+ struct dp_mon_mpdu *mon_mpdu,
+ struct hal_rx_mon_ppdu_info *ppduinfo,
+ struct napi_struct *napi)
{
struct sk_buff *mon_skb, *skb_next, *header;
struct ieee80211_rx_status *rxs = &dp_pdev->rx_status;
@@ -2412,8 +2374,9 @@ static int ath12k_dp_mon_rx_deliver(struct ath12k_pdev_dp *dp_pdev,
}
return -EINVAL;
}
+EXPORT_SYMBOL(ath12k_dp_mon_rx_deliver);
-static int ath12k_dp_pkt_set_pktlen(struct sk_buff *skb, u32 len)
+int ath12k_dp_pkt_set_pktlen(struct sk_buff *skb, u32 len)
{
if (skb->len > len) {
skb_trim(skb, len);
@@ -2430,6 +2393,7 @@ static int ath12k_dp_pkt_set_pktlen(struct sk_buff *skb, u32 len)
return 0;
}
+EXPORT_SYMBOL(ath12k_dp_pkt_set_pktlen);
/* Hardware fill buffer with 128 bytes aligned. So need to reap it
* with 128 bytes aligned.
@@ -2503,7 +2467,7 @@ ath12k_dp_mon_parse_status_buf(struct ath12k_pdev_dp *dp_pdev,
return 0;
}
-static int
+int
ath12k_dp_mon_parse_rx_dest_tlv(struct ath12k_pdev_dp *dp_pdev,
struct ath12k_mon_data *pmon,
enum hal_rx_mon_status hal_status,
@@ -2540,87 +2504,7 @@ ath12k_dp_mon_parse_rx_dest_tlv(struct ath12k_pdev_dp *dp_pdev,
return 0;
}
-
-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)
-{
- struct ath12k *ar = ath12k_pdev_dp_to_ar(dp_pdev);
- struct hal_tlv_64_hdr *tlv;
- struct ath12k_skb_rxcb *rxcb;
- enum hal_rx_mon_status hal_status;
- u16 tlv_tag, tlv_len;
- u8 *ptr = skb->data;
-
- do {
- tlv = (struct hal_tlv_64_hdr *)ptr;
- tlv_tag = le64_get_bits(tlv->tl, HAL_TLV_64_HDR_TAG);
-
- /* The actual length of PPDU_END is the combined length of many PHY
- * TLVs that follow. Skip the TLV header and
- * rx_rxpcu_classification_overview that follows the header to get to
- * next TLV.
- */
-
- if (tlv_tag == HAL_RX_PPDU_END)
- tlv_len = sizeof(struct hal_rx_rxpcu_classification_overview);
- else
- tlv_len = le64_get_bits(tlv->tl, HAL_TLV_64_HDR_LEN);
-
- hal_status = ath12k_dp_mon_rx_parse_status_tlv(dp_pdev, pmon, tlv);
-
- if (ar->monitor_started && ar->ab->hw_params->rxdma1_enable &&
- ath12k_dp_mon_parse_rx_dest_tlv(dp_pdev, pmon, hal_status,
- tlv->value))
- return HAL_RX_MON_STATUS_PPDU_DONE;
-
- ptr += sizeof(*tlv) + tlv_len;
- ptr = PTR_ALIGN(ptr, HAL_TLV_64_ALIGN);
-
- if ((ptr - skb->data) > skb->len)
- break;
-
- } while ((hal_status == HAL_RX_MON_STATUS_PPDU_NOT_DONE) ||
- (hal_status == HAL_RX_MON_STATUS_BUF_ADDR) ||
- (hal_status == HAL_RX_MON_STATUS_MPDU_START) ||
- (hal_status == HAL_RX_MON_STATUS_MPDU_END) ||
- (hal_status == HAL_RX_MON_STATUS_MSDU_END));
-
- rxcb = ATH12K_SKB_RXCB(skb);
- if (rxcb->is_end_of_ppdu)
- hal_status = HAL_RX_MON_STATUS_PPDU_DONE;
-
- 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,
- struct ath12k_mon_data *pmon,
- struct sk_buff *skb,
- struct napi_struct *napi)
-{
- struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info;
- struct dp_mon_mpdu *tmp;
- struct dp_mon_mpdu *mon_mpdu = pmon->mon_mpdu;
- enum hal_rx_mon_status hal_status;
-
- hal_status = ath12k_dp_mon_parse_rx_dest(dp_pdev, pmon, skb);
- if (hal_status != HAL_RX_MON_STATUS_PPDU_DONE)
- return hal_status;
-
- list_for_each_entry_safe(mon_mpdu, tmp, &pmon->dp_rx_mon_mpdu_list, list) {
- list_del(&mon_mpdu->list);
-
- if (mon_mpdu->head && mon_mpdu->tail)
- ath12k_dp_mon_rx_deliver(dp_pdev, mon_mpdu, ppdu_info, napi);
-
- kfree(mon_mpdu);
- }
-
- return hal_status;
-}
-EXPORT_SYMBOL(ath12k_dp_mon_rx_parse_mon_status);
+EXPORT_SYMBOL(ath12k_dp_mon_parse_rx_dest_tlv);
int ath12k_dp_mon_buf_replenish(struct ath12k_base *ab,
struct dp_rxdma_mon_ring *buf_ring,
@@ -3766,161 +3650,7 @@ ath12k_dp_mon_rx_update_peer_mu_stats(struct ath12k_base *ab,
}
EXPORT_SYMBOL(ath12k_dp_mon_rx_update_peer_mu_stats);
-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_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;
- enum dp_mon_status_buf_state reap_status;
- struct dp_rxdma_mon_ring *rx_ring;
- struct ath12k_mon_data *pmon;
- struct ath12k_skb_rxcb *rxcb;
- struct hal_tlv_64_hdr *tlv;
- void *rx_mon_status_desc;
- struct hal_srng *srng;
- struct ath12k_dp *dp;
- struct sk_buff *skb;
- struct ath12k *ar;
- dma_addr_t paddr;
- u32 cookie;
- u8 rbm;
-
- ar = ab->pdevs[ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id)].ar;
- dp = ath12k_ab_to_dp(ab);
- pmon = &ar->dp.mon_data;
- srng_id = ath12k_hw_mac_id_to_srng_id(ab->hw_params, mac_id);
- rx_ring = &dp->rx_mon_status_refill_ring[srng_id];
-
- srng = &ab->hal.srng_list[rx_ring->refill_buf_ring.ring_id];
-
- spin_lock_bh(&srng->lock);
-
- ath12k_hal_srng_access_begin(ab, srng);
-
- while (*budget) {
- *budget -= 1;
- rx_mon_status_desc = ath12k_hal_srng_src_peek(ab, srng);
- if (!rx_mon_status_desc) {
- pmon->buf_state = DP_MON_STATUS_REPLINISH;
- break;
- }
- ath12k_hal_rx_buf_addr_info_get(&ab->hal, rx_mon_status_desc, &paddr,
- &cookie, &rbm);
- if (paddr) {
- buf_id = u32_get_bits(cookie, DP_RXDMA_BUF_COOKIE_BUF_ID);
-
- spin_lock_bh(&rx_ring->idr_lock);
- skb = idr_find(&rx_ring->bufs_idr, buf_id);
- spin_unlock_bh(&rx_ring->idr_lock);
-
- if (!skb) {
- ath12k_warn(ab, "rx monitor status with invalid buf_id %d\n",
- buf_id);
- pmon->buf_state = DP_MON_STATUS_REPLINISH;
- goto move_next;
- }
-
- rxcb = ATH12K_SKB_RXCB(skb);
-
- dma_sync_single_for_cpu(ab->dev, rxcb->paddr,
- skb->len + skb_tailroom(skb),
- DMA_FROM_DEVICE);
-
- tlv = (struct hal_tlv_64_hdr *)skb->data;
- if (le64_get_bits(tlv->tl, HAL_TLV_HDR_TAG) !=
- HAL_RX_STATUS_BUFFER_DONE) {
- pmon->buf_state = DP_MON_STATUS_NO_DMA;
- ath12k_warn(ab,
- "mon status DONE not set %llx, buf_id %d\n",
- le64_get_bits(tlv->tl, HAL_TLV_HDR_TAG),
- buf_id);
- /* RxDMA status done bit might not be set even
- * though tp is moved by HW.
- */
-
- /* If done status is missing:
- * 1. As per MAC team's suggestion,
- * when HP + 1 entry is peeked and if DMA
- * is not done and if HP + 2 entry's DMA done
- * is set. skip HP + 1 entry and
- * start processing in next interrupt.
- * 2. If HP + 2 entry's DMA done is not set,
- * poll onto HP + 1 entry DMA done to be set.
- * Check status for same buffer for next time
- * dp_rx_mon_status_srng_process
- */
- reap_status = ath12k_dp_rx_mon_buf_done(ab, srng,
- rx_ring);
- if (reap_status == DP_MON_STATUS_NO_DMA)
- continue;
-
- spin_lock_bh(&rx_ring->idr_lock);
- idr_remove(&rx_ring->bufs_idr, buf_id);
- spin_unlock_bh(&rx_ring->idr_lock);
-
- dma_unmap_single(ab->dev, rxcb->paddr,
- skb->len + skb_tailroom(skb),
- DMA_FROM_DEVICE);
-
- dev_kfree_skb_any(skb);
- pmon->buf_state = DP_MON_STATUS_REPLINISH;
- goto move_next;
- }
-
- spin_lock_bh(&rx_ring->idr_lock);
- idr_remove(&rx_ring->bufs_idr, buf_id);
- spin_unlock_bh(&rx_ring->idr_lock);
-
- dma_unmap_single(ab->dev, rxcb->paddr,
- skb->len + skb_tailroom(skb),
- DMA_FROM_DEVICE);
-
- if (ath12k_dp_pkt_set_pktlen(skb, RX_MON_STATUS_BUF_SIZE)) {
- dev_kfree_skb_any(skb);
- goto move_next;
- }
- __skb_queue_tail(skb_list, skb);
- } else {
- pmon->buf_state = DP_MON_STATUS_REPLINISH;
- }
-move_next:
- skb = ath12k_dp_rx_alloc_mon_status_buf(ab, rx_ring,
- &buf_id);
- hal_params = ab->hal.hal_params;
-
- if (!skb) {
- ath12k_warn(ab, "failed to alloc buffer for status ring\n");
- ath12k_hal_rx_buf_addr_info_set(&ab->hal, rx_mon_status_desc,
- 0, 0, hal_params->rx_buf_rbm);
- num_buffs_reaped++;
- break;
- }
- rxcb = ATH12K_SKB_RXCB(skb);
-
- cookie = u32_encode_bits(mac_id, DP_RXDMA_BUF_COOKIE_PDEV_ID) |
- u32_encode_bits(buf_id, DP_RXDMA_BUF_COOKIE_BUF_ID);
-
- ath12k_hal_rx_buf_addr_info_set(&ab->hal, rx_mon_status_desc, rxcb->paddr,
- cookie, hal_params->rx_buf_rbm);
- ath12k_hal_srng_src_get_next_entry(ab, srng);
- num_buffs_reaped++;
- }
- ath12k_hal_srng_access_end(ab, srng);
- spin_unlock_bh(&srng->lock);
-
- return num_buffs_reaped;
-}
-EXPORT_SYMBOL(ath12k_dp_rx_reap_mon_status_ring);
-
-static u32
+u32
ath12k_dp_rx_mon_mpdu_pop(struct ath12k *ar, int mac_id,
void *ring_entry, struct sk_buff **head_msdu,
struct sk_buff **tail_msdu,
@@ -4107,113 +3837,4 @@ ath12k_dp_rx_mon_mpdu_pop(struct ath12k *ar, int mac_id,
return rx_bufs_used;
}
-
-/* The destination ring processing is stuck if the destination is not
- * moving while status ring moves 16 PPDU. The destination ring processing
- * skips this destination ring PPDU as a workaround.
- */
-#define MON_DEST_RING_STUCK_MAX_CNT 16
-
-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;
- u32 ppdu_id, rx_bufs_used = 0, ring_id;
- u32 mpdu_rx_bufs_used, npackets = 0;
- struct ath12k_base *ab = ar->ab;
- struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
- void *ring_entry, *mon_dst_srng;
- struct dp_mon_mpdu *tmp_mpdu;
- LIST_HEAD(rx_desc_used_list);
- struct hal_srng *srng;
-
- ring_id = dp->rxdma_err_dst_ring[mac_id].ring_id;
- srng = &ab->hal.srng_list[ring_id];
-
- mon_dst_srng = &ab->hal.srng_list[ring_id];
-
- spin_lock_bh(&srng->lock);
-
- ath12k_hal_srng_access_begin(ab, mon_dst_srng);
-
- ppdu_id = pmon->mon_ppdu_info.ppdu_id;
- rx_mon_stats = &pmon->rx_mon_stats;
-
- while ((ring_entry = ath12k_hal_srng_dst_peek(ar->ab, mon_dst_srng))) {
- struct sk_buff *head_msdu, *tail_msdu;
-
- head_msdu = NULL;
- tail_msdu = NULL;
-
- mpdu_rx_bufs_used = ath12k_dp_rx_mon_mpdu_pop(ar, mac_id, ring_entry,
- &head_msdu, &tail_msdu,
- &rx_desc_used_list,
- &npackets, &ppdu_id);
-
- rx_bufs_used += mpdu_rx_bufs_used;
-
- if (mpdu_rx_bufs_used) {
- dp->mon_dest_ring_stuck_cnt = 0;
- } else {
- dp->mon_dest_ring_stuck_cnt++;
- rx_mon_stats->dest_mon_not_reaped++;
- }
-
- if (dp->mon_dest_ring_stuck_cnt > MON_DEST_RING_STUCK_MAX_CNT) {
- rx_mon_stats->dest_mon_stuck++;
- ath12k_dbg(ar->ab, ATH12K_DBG_DATA,
- "status ring ppdu_id=%d dest ring ppdu_id=%d mon_dest_ring_stuck_cnt=%d dest_mon_not_reaped=%u dest_mon_stuck=%u\n",
- pmon->mon_ppdu_info.ppdu_id, ppdu_id,
- dp->mon_dest_ring_stuck_cnt,
- rx_mon_stats->dest_mon_not_reaped,
- rx_mon_stats->dest_mon_stuck);
- spin_lock_bh(&pmon->mon_lock);
- pmon->mon_ppdu_info.ppdu_id = ppdu_id;
- spin_unlock_bh(&pmon->mon_lock);
- continue;
- }
-
- if (ppdu_id != pmon->mon_ppdu_info.ppdu_id) {
- spin_lock_bh(&pmon->mon_lock);
- pmon->mon_ppdu_status = DP_PPDU_STATUS_START;
- spin_unlock_bh(&pmon->mon_lock);
- ath12k_dbg(ar->ab, ATH12K_DBG_DATA,
- "dest_rx: new ppdu_id %x != status ppdu_id %x dest_mon_not_reaped = %u dest_mon_stuck = %u\n",
- ppdu_id, pmon->mon_ppdu_info.ppdu_id,
- rx_mon_stats->dest_mon_not_reaped,
- rx_mon_stats->dest_mon_stuck);
- break;
- }
-
- if (head_msdu && tail_msdu) {
- tmp_mpdu = kzalloc(sizeof(*tmp_mpdu), GFP_ATOMIC);
- if (!tmp_mpdu)
- break;
-
- tmp_mpdu->head = head_msdu;
- tmp_mpdu->tail = tail_msdu;
- tmp_mpdu->err_bitmap = pmon->err_bitmap;
- tmp_mpdu->decap_format = pmon->decap_format;
- ath12k_dp_mon_rx_deliver(&ar->dp, tmp_mpdu,
- &pmon->mon_ppdu_info, napi);
- rx_mon_stats->dest_mpdu_done++;
- kfree(tmp_mpdu);
- }
-
- ring_entry = ath12k_hal_srng_dst_get_next_entry(ar->ab,
- mon_dst_srng);
- }
- ath12k_hal_srng_access_end(ar->ab, mon_dst_srng);
-
- spin_unlock_bh(&srng->lock);
-
- if (rx_bufs_used) {
- rx_mon_stats->dest_ppdu_done++;
- ath12k_dp_rx_bufs_replenish(ar->ab->dp,
- &dp->rx_refill_buf_ring,
- &rx_desc_used_list,
- rx_bufs_used);
- }
-}
-EXPORT_SYMBOL(ath12k_dp_rx_mon_dest_process);
+EXPORT_SYMBOL(ath12k_dp_rx_mon_mpdu_pop);
diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.h b/drivers/net/wireless/ath/ath12k/dp_mon.h
index 689d7a0fff5c..726434ab74ac 100644
--- a/drivers/net/wireless/ath/ath12k/dp_mon.h
+++ b/drivers/net/wireless/ath/ath12k/dp_mon.h
@@ -78,11 +78,6 @@ struct dp_mon_tx_ppdu_info {
struct dp_mon_mpdu *tx_mon_mpdu;
};
-enum hal_rx_mon_status
-ath12k_dp_mon_rx_parse_mon_status(struct ath12k_pdev_dp *dp_pdev,
- struct ath12k_mon_data *pmon,
- struct sk_buff *skb,
- struct napi_struct *napi);
int ath12k_dp_mon_buf_replenish(struct ath12k_base *ab,
struct dp_rxdma_mon_ring *buf_ring,
int req_entries);
@@ -101,18 +96,33 @@ 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);
-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);
+u32
+ath12k_dp_rx_mon_mpdu_pop(struct ath12k *ar, int mac_id,
+ void *ring_entry, struct sk_buff **head_msdu,
+ struct sk_buff **tail_msdu,
+ struct list_head *used_list,
+ u32 *npackets, u32 *ppdu_id);
+int ath12k_dp_pkt_set_pktlen(struct sk_buff *skb, u32 len);
+int ath12k_dp_mon_rx_deliver(struct ath12k_pdev_dp *dp_pdev,
+ struct dp_mon_mpdu *mon_mpdu,
+ struct hal_rx_mon_ppdu_info *ppduinfo,
+ struct napi_struct *napi);
+int
+ath12k_dp_mon_parse_rx_dest_tlv(struct ath12k_pdev_dp *dp_pdev,
+ struct ath12k_mon_data *pmon,
+ enum hal_rx_mon_status hal_status,
+ const void *tlv_data);
+enum hal_rx_mon_status
+ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_pdev_dp *dp_pdev,
+ struct ath12k_mon_data *pmon,
+ const struct hal_tlv_64_hdr *tlv);
+struct sk_buff
+*ath12k_dp_rx_alloc_mon_status_buf(struct ath12k_base *ab,
+ struct dp_rxdma_mon_ring *rx_ring,
+ int *buf_id);
#endif
diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c
index efa039f6df92..91d697ad1799 100644
--- a/drivers/net/wireless/ath/ath12k/hal.c
+++ b/drivers/net/wireless/ath/ath12k/hal.c
@@ -402,6 +402,7 @@ void *ath12k_hal_srng_src_next_peek(struct ath12k_base *ab,
return desc;
}
+EXPORT_SYMBOL(ath12k_hal_srng_src_next_peek);
void *ath12k_hal_srng_src_get_next_entry(struct ath12k_base *ab,
struct hal_srng *srng)
@@ -447,6 +448,7 @@ void *ath12k_hal_srng_src_peek(struct ath12k_base *ab, struct hal_srng *srng)
return srng->ring_base_vaddr + srng->u.src_ring.hp;
}
+EXPORT_SYMBOL(ath12k_hal_srng_src_peek);
void *ath12k_hal_srng_src_reap_next(struct ath12k_base *ab,
struct hal_srng *srng)
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c
index 4135ff5e8759..ffebeb1652e7 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c
@@ -12,6 +12,390 @@
#include "dp_rx.h"
#include "../peer.h"
+static void
+ath12k_wifi7_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;
+}
+
+/* The destination ring processing is stuck if the destination is not
+ * moving while status ring moves 16 PPDU. The destination ring processing
+ * skips this destination ring PPDU as a workaround.
+ */
+#define MON_DEST_RING_STUCK_MAX_CNT 16
+
+static void
+ath12k_wifi7_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;
+ u32 ppdu_id, rx_bufs_used = 0, ring_id;
+ u32 mpdu_rx_bufs_used, npackets = 0;
+ struct ath12k_base *ab = ar->ab;
+ struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
+ void *ring_entry, *mon_dst_srng;
+ struct dp_mon_mpdu *tmp_mpdu;
+ LIST_HEAD(rx_desc_used_list);
+ struct hal_srng *srng;
+
+ ring_id = dp->rxdma_err_dst_ring[mac_id].ring_id;
+ srng = &ab->hal.srng_list[ring_id];
+
+ mon_dst_srng = &ab->hal.srng_list[ring_id];
+
+ spin_lock_bh(&srng->lock);
+
+ ath12k_hal_srng_access_begin(ab, mon_dst_srng);
+
+ ppdu_id = pmon->mon_ppdu_info.ppdu_id;
+ rx_mon_stats = &pmon->rx_mon_stats;
+
+ while ((ring_entry = ath12k_hal_srng_dst_peek(ar->ab, mon_dst_srng))) {
+ struct sk_buff *head_msdu, *tail_msdu;
+
+ head_msdu = NULL;
+ tail_msdu = NULL;
+
+ mpdu_rx_bufs_used = ath12k_dp_rx_mon_mpdu_pop(ar, mac_id, ring_entry,
+ &head_msdu, &tail_msdu,
+ &rx_desc_used_list,
+ &npackets, &ppdu_id);
+
+ rx_bufs_used += mpdu_rx_bufs_used;
+
+ if (mpdu_rx_bufs_used) {
+ dp->mon_dest_ring_stuck_cnt = 0;
+ } else {
+ dp->mon_dest_ring_stuck_cnt++;
+ rx_mon_stats->dest_mon_not_reaped++;
+ }
+
+ if (dp->mon_dest_ring_stuck_cnt > MON_DEST_RING_STUCK_MAX_CNT) {
+ rx_mon_stats->dest_mon_stuck++;
+ ath12k_dbg(ar->ab, ATH12K_DBG_DATA,
+ "status ring ppdu_id=%d dest ring ppdu_id=%d mon_dest_ring_stuck_cnt=%d dest_mon_not_reaped=%u dest_mon_stuck=%u\n",
+ pmon->mon_ppdu_info.ppdu_id, ppdu_id,
+ dp->mon_dest_ring_stuck_cnt,
+ rx_mon_stats->dest_mon_not_reaped,
+ rx_mon_stats->dest_mon_stuck);
+ spin_lock_bh(&pmon->mon_lock);
+ pmon->mon_ppdu_info.ppdu_id = ppdu_id;
+ spin_unlock_bh(&pmon->mon_lock);
+ continue;
+ }
+
+ if (ppdu_id != pmon->mon_ppdu_info.ppdu_id) {
+ spin_lock_bh(&pmon->mon_lock);
+ pmon->mon_ppdu_status = DP_PPDU_STATUS_START;
+ spin_unlock_bh(&pmon->mon_lock);
+ ath12k_dbg(ar->ab, ATH12K_DBG_DATA,
+ "dest_rx: new ppdu_id %x != status ppdu_id %x dest_mon_not_reaped = %u dest_mon_stuck = %u\n",
+ ppdu_id, pmon->mon_ppdu_info.ppdu_id,
+ rx_mon_stats->dest_mon_not_reaped,
+ rx_mon_stats->dest_mon_stuck);
+ break;
+ }
+
+ if (head_msdu && tail_msdu) {
+ tmp_mpdu = kzalloc(sizeof(*tmp_mpdu), GFP_ATOMIC);
+ if (!tmp_mpdu)
+ break;
+
+ tmp_mpdu->head = head_msdu;
+ tmp_mpdu->tail = tail_msdu;
+ tmp_mpdu->err_bitmap = pmon->err_bitmap;
+ tmp_mpdu->decap_format = pmon->decap_format;
+ ath12k_dp_mon_rx_deliver(&ar->dp, tmp_mpdu,
+ &pmon->mon_ppdu_info, napi);
+ rx_mon_stats->dest_mpdu_done++;
+ kfree(tmp_mpdu);
+ }
+
+ ring_entry = ath12k_hal_srng_dst_get_next_entry(ar->ab,
+ mon_dst_srng);
+ }
+ ath12k_hal_srng_access_end(ar->ab, mon_dst_srng);
+
+ spin_unlock_bh(&srng->lock);
+
+ if (rx_bufs_used) {
+ rx_mon_stats->dest_ppdu_done++;
+ ath12k_dp_rx_bufs_replenish(ar->ab->dp,
+ &dp->rx_refill_buf_ring,
+ &rx_desc_used_list,
+ rx_bufs_used);
+ }
+}
+
+static enum dp_mon_status_buf_state
+ath12k_wifi7_dp_rx_mon_buf_done(struct ath12k_base *ab, struct hal_srng *srng,
+ struct dp_rxdma_mon_ring *rx_ring)
+{
+ struct ath12k_skb_rxcb *rxcb;
+ struct hal_tlv_64_hdr *tlv;
+ struct sk_buff *skb;
+ void *status_desc;
+ dma_addr_t paddr;
+ u32 cookie;
+ int buf_id;
+ u8 rbm;
+
+ status_desc = ath12k_hal_srng_src_next_peek(ab, srng);
+ if (!status_desc)
+ return DP_MON_STATUS_NO_DMA;
+
+ ath12k_wifi7_hal_rx_buf_addr_info_get(status_desc, &paddr, &cookie, &rbm);
+
+ buf_id = u32_get_bits(cookie, DP_RXDMA_BUF_COOKIE_BUF_ID);
+
+ spin_lock_bh(&rx_ring->idr_lock);
+ skb = idr_find(&rx_ring->bufs_idr, buf_id);
+ spin_unlock_bh(&rx_ring->idr_lock);
+
+ if (!skb)
+ return DP_MON_STATUS_NO_DMA;
+
+ rxcb = ATH12K_SKB_RXCB(skb);
+ dma_sync_single_for_cpu(ab->dev, rxcb->paddr,
+ skb->len + skb_tailroom(skb),
+ DMA_FROM_DEVICE);
+
+ tlv = (struct hal_tlv_64_hdr *)skb->data;
+ if (le64_get_bits(tlv->tl, HAL_TLV_HDR_TAG) != HAL_RX_STATUS_BUFFER_DONE)
+ return DP_MON_STATUS_NO_DMA;
+
+ return DP_MON_STATUS_REPLINISH;
+}
+
+static enum hal_rx_mon_status
+ath12k_wifi7_dp_mon_parse_rx_dest(struct ath12k_pdev_dp *dp_pdev,
+ struct ath12k_mon_data *pmon,
+ struct sk_buff *skb)
+{
+ struct ath12k *ar = ath12k_pdev_dp_to_ar(dp_pdev);
+ struct hal_tlv_64_hdr *tlv;
+ struct ath12k_skb_rxcb *rxcb;
+ enum hal_rx_mon_status hal_status;
+ u16 tlv_tag, tlv_len;
+ u8 *ptr = skb->data;
+
+ do {
+ tlv = (struct hal_tlv_64_hdr *)ptr;
+ tlv_tag = le64_get_bits(tlv->tl, HAL_TLV_64_HDR_TAG);
+
+ /* The actual length of PPDU_END is the combined length of many PHY
+ * TLVs that follow. Skip the TLV header and
+ * rx_rxpcu_classification_overview that follows the header to get to
+ * next TLV.
+ */
+
+ if (tlv_tag == HAL_RX_PPDU_END)
+ tlv_len = sizeof(struct hal_rx_rxpcu_classification_overview);
+ else
+ tlv_len = le64_get_bits(tlv->tl, HAL_TLV_64_HDR_LEN);
+
+ hal_status = ath12k_dp_mon_rx_parse_status_tlv(dp_pdev, pmon, tlv);
+
+ if (ar->monitor_started && ar->ab->hw_params->rxdma1_enable &&
+ ath12k_dp_mon_parse_rx_dest_tlv(dp_pdev, pmon, hal_status,
+ tlv->value))
+ return HAL_RX_MON_STATUS_PPDU_DONE;
+
+ ptr += sizeof(*tlv) + tlv_len;
+ ptr = PTR_ALIGN(ptr, HAL_TLV_64_ALIGN);
+
+ if ((ptr - skb->data) > skb->len)
+ break;
+
+ } while ((hal_status == HAL_RX_MON_STATUS_PPDU_NOT_DONE) ||
+ (hal_status == HAL_RX_MON_STATUS_BUF_ADDR) ||
+ (hal_status == HAL_RX_MON_STATUS_MPDU_START) ||
+ (hal_status == HAL_RX_MON_STATUS_MPDU_END) ||
+ (hal_status == HAL_RX_MON_STATUS_MSDU_END));
+
+ rxcb = ATH12K_SKB_RXCB(skb);
+ if (rxcb->is_end_of_ppdu)
+ hal_status = HAL_RX_MON_STATUS_PPDU_DONE;
+
+ return hal_status;
+}
+
+static enum hal_rx_mon_status
+ath12k_wifi7_dp_mon_rx_parse_mon_status(struct ath12k_pdev_dp *dp_pdev,
+ struct ath12k_mon_data *pmon,
+ struct sk_buff *skb,
+ struct napi_struct *napi)
+{
+ struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info;
+ struct dp_mon_mpdu *tmp;
+ struct dp_mon_mpdu *mon_mpdu = pmon->mon_mpdu;
+ enum hal_rx_mon_status hal_status;
+
+ hal_status = ath12k_wifi7_dp_mon_parse_rx_dest(dp_pdev, pmon, skb);
+ if (hal_status != HAL_RX_MON_STATUS_PPDU_DONE)
+ return hal_status;
+
+ list_for_each_entry_safe(mon_mpdu, tmp, &pmon->dp_rx_mon_mpdu_list, list) {
+ list_del(&mon_mpdu->list);
+
+ if (mon_mpdu->head && mon_mpdu->tail)
+ ath12k_dp_mon_rx_deliver(dp_pdev, mon_mpdu, ppdu_info, napi);
+
+ kfree(mon_mpdu);
+ }
+
+ return hal_status;
+}
+
+static int
+ath12k_wifi7_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;
+ enum dp_mon_status_buf_state reap_status;
+ struct dp_rxdma_mon_ring *rx_ring;
+ struct ath12k_mon_data *pmon;
+ struct ath12k_skb_rxcb *rxcb;
+ struct hal_tlv_64_hdr *tlv;
+ void *rx_mon_status_desc;
+ struct hal_srng *srng;
+ struct ath12k_dp *dp;
+ struct sk_buff *skb;
+ struct ath12k *ar;
+ dma_addr_t paddr;
+ u32 cookie;
+ u8 rbm;
+
+ ar = ab->pdevs[ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id)].ar;
+ dp = ath12k_ab_to_dp(ab);
+ pmon = &ar->dp.mon_data;
+ srng_id = ath12k_hw_mac_id_to_srng_id(ab->hw_params, mac_id);
+ rx_ring = &dp->rx_mon_status_refill_ring[srng_id];
+
+ srng = &ab->hal.srng_list[rx_ring->refill_buf_ring.ring_id];
+
+ spin_lock_bh(&srng->lock);
+
+ ath12k_hal_srng_access_begin(ab, srng);
+
+ while (*budget) {
+ *budget -= 1;
+ rx_mon_status_desc = ath12k_hal_srng_src_peek(ab, srng);
+ if (!rx_mon_status_desc) {
+ pmon->buf_state = DP_MON_STATUS_REPLINISH;
+ break;
+ }
+ ath12k_wifi7_hal_rx_buf_addr_info_get(rx_mon_status_desc, &paddr,
+ &cookie, &rbm);
+ if (paddr) {
+ buf_id = u32_get_bits(cookie, DP_RXDMA_BUF_COOKIE_BUF_ID);
+
+ spin_lock_bh(&rx_ring->idr_lock);
+ skb = idr_find(&rx_ring->bufs_idr, buf_id);
+ spin_unlock_bh(&rx_ring->idr_lock);
+
+ if (!skb) {
+ ath12k_warn(ab, "rx monitor status with invalid buf_id %d\n",
+ buf_id);
+ pmon->buf_state = DP_MON_STATUS_REPLINISH;
+ goto move_next;
+ }
+
+ rxcb = ATH12K_SKB_RXCB(skb);
+
+ dma_sync_single_for_cpu(ab->dev, rxcb->paddr,
+ skb->len + skb_tailroom(skb),
+ DMA_FROM_DEVICE);
+
+ tlv = (struct hal_tlv_64_hdr *)skb->data;
+ if (le64_get_bits(tlv->tl, HAL_TLV_HDR_TAG) !=
+ HAL_RX_STATUS_BUFFER_DONE) {
+ pmon->buf_state = DP_MON_STATUS_NO_DMA;
+ ath12k_warn(ab,
+ "mon status DONE not set %llx, buf_id %d\n",
+ le64_get_bits(tlv->tl, HAL_TLV_HDR_TAG),
+ buf_id);
+ /* RxDMA status done bit might not be set even
+ * though tp is moved by HW.
+ */
+
+ /* If done status is missing:
+ * 1. As per MAC team's suggestion,
+ * when HP + 1 entry is peeked and if DMA
+ * is not done and if HP + 2 entry's DMA done
+ * is set. skip HP + 1 entry and
+ * start processing in next interrupt.
+ * 2. If HP + 2 entry's DMA done is not set,
+ * poll onto HP + 1 entry DMA done to be set.
+ * Check status for same buffer for next time
+ * dp_rx_mon_status_srng_process
+ */
+ reap_status = ath12k_wifi7_dp_rx_mon_buf_done(ab, srng,
+ rx_ring);
+ if (reap_status == DP_MON_STATUS_NO_DMA)
+ continue;
+
+ spin_lock_bh(&rx_ring->idr_lock);
+ idr_remove(&rx_ring->bufs_idr, buf_id);
+ spin_unlock_bh(&rx_ring->idr_lock);
+
+ dma_unmap_single(ab->dev, rxcb->paddr,
+ skb->len + skb_tailroom(skb),
+ DMA_FROM_DEVICE);
+
+ dev_kfree_skb_any(skb);
+ pmon->buf_state = DP_MON_STATUS_REPLINISH;
+ goto move_next;
+ }
+
+ spin_lock_bh(&rx_ring->idr_lock);
+ idr_remove(&rx_ring->bufs_idr, buf_id);
+ spin_unlock_bh(&rx_ring->idr_lock);
+
+ dma_unmap_single(ab->dev, rxcb->paddr,
+ skb->len + skb_tailroom(skb),
+ DMA_FROM_DEVICE);
+
+ if (ath12k_dp_pkt_set_pktlen(skb, RX_MON_STATUS_BUF_SIZE)) {
+ dev_kfree_skb_any(skb);
+ goto move_next;
+ }
+ __skb_queue_tail(skb_list, skb);
+ } else {
+ pmon->buf_state = DP_MON_STATUS_REPLINISH;
+ }
+move_next:
+ skb = ath12k_dp_rx_alloc_mon_status_buf(ab, rx_ring,
+ &buf_id);
+ hal_params = ab->hal.hal_params;
+
+ if (!skb) {
+ ath12k_warn(ab, "failed to alloc buffer for status ring\n");
+ ath12k_wifi7_hal_rx_buf_addr_info_set(rx_mon_status_desc,
+ 0, 0,
+ hal_params->rx_buf_rbm);
+ num_buffs_reaped++;
+ break;
+ }
+ rxcb = ATH12K_SKB_RXCB(skb);
+
+ cookie = u32_encode_bits(mac_id, DP_RXDMA_BUF_COOKIE_PDEV_ID) |
+ u32_encode_bits(buf_id, DP_RXDMA_BUF_COOKIE_BUF_ID);
+
+ ath12k_wifi7_hal_rx_buf_addr_info_set(rx_mon_status_desc, rxcb->paddr,
+ cookie, hal_params->rx_buf_rbm);
+ ath12k_hal_srng_src_get_next_entry(ab, srng);
+ num_buffs_reaped++;
+ }
+ ath12k_hal_srng_access_end(ab, srng);
+ spin_unlock_bh(&srng->lock);
+
+ return num_buffs_reaped;
+}
+
static int
__ath12k_wifi7_dp_mon_process_ring(struct ath12k *ar, int mac_id,
struct napi_struct *napi, int *budget)
@@ -26,8 +410,8 @@ __ath12k_wifi7_dp_mon_process_ring(struct ath12k *ar, int mac_id,
__skb_queue_head_init(&skb_list);
- num_buffs_reaped = ath12k_dp_rx_reap_mon_status_ring(ar->ab, mac_id,
- budget, &skb_list);
+ num_buffs_reaped = ath12k_wifi7_dp_rx_reap_mon_status_ring(ar->ab, mac_id,
+ budget, &skb_list);
if (!num_buffs_reaped)
goto exit;
@@ -35,14 +419,14 @@ __ath12k_wifi7_dp_mon_process_ring(struct ath12k *ar, int mac_id,
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);
+ hal_status = ath12k_wifi7_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);
+ ath12k_wifi7_dp_rx_mon_dest_process(ar, mac_id, *budget, napi);
pmon->mon_ppdu_status = DP_PPDU_STATUS_START;
}
@@ -167,10 +551,11 @@ ath12k_wifi7_dp_mon_srng_process(struct ath12k_pdev_dp *pdev_dp, int *budget,
* 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);
+ ath12k_wifi7_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);
+ hal_status = ath12k_wifi7_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);
@@ -201,7 +586,7 @@ ath12k_wifi7_dp_mon_srng_process(struct ath12k_pdev_dp *pdev_dp, int *budget,
rcu_read_unlock();
free_skb:
dev_kfree_skb_any(skb);
- ath12k_dp_mon_rx_memset_ppdu_info(ppdu_info);
+ ath12k_wifi7_dp_mon_rx_memset_ppdu_info(ppdu_info);
}
return num_buffs_reaped;
--
2.34.1
More information about the ath12k
mailing list