@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_DP_H
@@ -106,6 +106,8 @@ struct dp_mon_mpdu {
struct list_head list;
struct sk_buff *head;
struct sk_buff *tail;
+ u32 err_bitmap;
+ u8 decap_format;
};
#define DP_MON_MAX_STATUS_BUF 32
@@ -1676,7 +1676,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k *ar,
u32_get_bits(info[0], HAL_RX_MPDU_START_INFO0_PPDU_ID);
}
- break;
+ return HAL_RX_MON_STATUS_MPDU_START;
}
case HAL_RX_MSDU_START:
/* TODO: add msdu start parsing logic */
@@ -2119,6 +2119,144 @@ static int ath12k_dp_mon_rx_deliver(struct ath12k *ar,
return -EINVAL;
}
+static int ath12k_dp_pkt_set_pktlen(struct sk_buff *skb, u32 len)
+{
+ if (skb->len > len) {
+ skb_trim(skb, len);
+ } else {
+ if (skb_tailroom(skb) < len - skb->len) {
+ if ((pskb_expand_head(skb, 0,
+ len - skb->len - skb_tailroom(skb),
+ GFP_ATOMIC))) {
+ return -ENOMEM;
+ }
+ }
+ skb_put(skb, (len - skb->len));
+ }
+
+ return 0;
+}
+
+static void ath12k_dp_mon_parse_rx_msdu_end_err(u32 info, u32 *errmap)
+{
+ if (info & RX_MSDU_END_INFO13_FCS_ERR)
+ *errmap |= HAL_RX_MPDU_ERR_FCS;
+
+ if (info & RX_MSDU_END_INFO13_DECRYPT_ERR)
+ *errmap |= HAL_RX_MPDU_ERR_DECRYPT;
+
+ if (info & RX_MSDU_END_INFO13_TKIP_MIC_ERR)
+ *errmap |= HAL_RX_MPDU_ERR_TKIP_MIC;
+
+ if (info & RX_MSDU_END_INFO13_A_MSDU_ERROR)
+ *errmap |= HAL_RX_MPDU_ERR_AMSDU_ERR;
+
+ if (info & RX_MSDU_END_INFO13_OVERFLOW_ERR)
+ *errmap |= HAL_RX_MPDU_ERR_OVERFLOW;
+
+ if (info & RX_MSDU_END_INFO13_MSDU_LEN_ERR)
+ *errmap |= HAL_RX_MPDU_ERR_MSDU_LEN;
+
+ if (info & RX_MSDU_END_INFO13_MPDU_LEN_ERR)
+ *errmap |= HAL_RX_MPDU_ERR_MPDU_LEN;
+}
+
+static int
+ath12k_dp_mon_parse_status_msdu_end(struct ath12k_mon_data *pmon,
+ const struct hal_rx_msdu_end *msdu_end)
+{
+ struct dp_mon_mpdu *mon_mpdu = pmon->mon_mpdu;
+
+ ath12k_dp_mon_parse_rx_msdu_end_err(__le32_to_cpu(msdu_end->info2),
+ &mon_mpdu->err_bitmap);
+
+ mon_mpdu->decap_format = le32_get_bits(msdu_end->info1,
+ RX_MSDU_END_INFO11_DECAP_FORMAT);
+
+ return 0;
+}
+
+static int
+ath12k_dp_mon_parse_status_buf(struct ath12k *ar,
+ struct ath12k_mon_data *pmon,
+ const struct dp_mon_packet_info *packet_info)
+{
+ struct ath12k_base *ab = ar->ab;
+ struct dp_rxdma_mon_ring *buf_ring = &ab->dp.rxdma_mon_buf_ring;
+ struct sk_buff *msdu;
+ int buf_id;
+ u32 offset;
+
+ buf_id = u32_get_bits(packet_info->cookie, DP_RXDMA_BUF_COOKIE_BUF_ID);
+
+ spin_lock_bh(&buf_ring->idr_lock);
+ msdu = idr_remove(&buf_ring->bufs_idr, buf_id);
+ spin_unlock_bh(&buf_ring->idr_lock);
+
+ if (unlikely(!msdu)) {
+ ath12k_warn(ab, "mon dest desc with inval buf_id %d\n", buf_id);
+ return 0;
+ }
+
+ dma_unmap_single(ab->dev, ATH12K_SKB_RXCB(msdu)->paddr,
+ msdu->len + skb_tailroom(msdu),
+ DMA_FROM_DEVICE);
+
+ offset = packet_info->dma_length + ATH12K_MON_RX_DOT11_OFFSET;
+ if (ath12k_dp_pkt_set_pktlen(msdu, offset)) {
+ dev_kfree_skb_any(msdu);
+ goto dest_replenish;
+ }
+
+ if (!pmon->mon_mpdu->head)
+ pmon->mon_mpdu->head = msdu;
+ else
+ pmon->mon_mpdu->tail->next = msdu;
+
+ pmon->mon_mpdu->tail = msdu;
+
+dest_replenish:
+ ath12k_dp_mon_buf_replenish(ab, buf_ring, 1);
+
+ return 0;
+}
+
+static int
+ath12k_dp_mon_parse_rx_dest_tlv(struct ath12k *ar,
+ struct ath12k_mon_data *pmon,
+ enum hal_rx_mon_status hal_status,
+ const void *tlv_data)
+{
+ switch (hal_status) {
+ case HAL_RX_MON_STATUS_MPDU_START:
+ if (WARN_ON_ONCE(pmon->mon_mpdu))
+ break;
+
+ pmon->mon_mpdu = kzalloc(sizeof(*pmon->mon_mpdu), GFP_ATOMIC);
+ if (!pmon->mon_mpdu)
+ return -ENOMEM;
+ break;
+ case HAL_RX_MON_STATUS_BUF_ADDR:
+ return ath12k_dp_mon_parse_status_buf(ar, pmon, tlv_data);
+ case HAL_RX_MON_STATUS_MPDU_END:
+ /* If no MSDU then free empty MPDU */
+ if (pmon->mon_mpdu->tail) {
+ pmon->mon_mpdu->tail->next = NULL;
+ list_add_tail(&pmon->mon_mpdu->list, &pmon->dp_rx_mon_mpdu_list);
+ } else {
+ kfree(pmon->mon_mpdu);
+ }
+ pmon->mon_mpdu = NULL;
+ break;
+ case HAL_RX_MON_STATUS_MSDU_END:
+ return ath12k_dp_mon_parse_status_msdu_end(pmon, tlv_data);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static enum hal_rx_mon_status
ath12k_dp_mon_parse_rx_dest(struct ath12k *ar, struct ath12k_mon_data *pmon,
struct sk_buff *skb)
@@ -2145,14 +2283,20 @@ ath12k_dp_mon_parse_rx_dest(struct ath12k *ar, struct ath12k_mon_data *pmon,
tlv_len = le64_get_bits(tlv->tl, HAL_TLV_64_HDR_LEN);
hal_status = ath12k_dp_mon_rx_parse_status_tlv(ar, pmon, tlv);
+
+ if (ar->monitor_started &&
+ ath12k_dp_mon_parse_rx_dest_tlv(ar, 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) >= DP_RX_BUFFER_SIZE)
+ 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));
@@ -2173,9 +2317,11 @@ ath12k_dp_mon_rx_parse_mon_status(struct ath12k *ar,
struct dp_mon_mpdu *tmp;
struct dp_mon_mpdu *mon_mpdu = pmon->mon_mpdu;
struct sk_buff *head_msdu, *tail_msdu;
- enum hal_rx_mon_status hal_status = HAL_RX_MON_STATUS_BUF_DONE;
+ enum hal_rx_mon_status hal_status;
- ath12k_dp_mon_parse_rx_dest(ar, pmon, skb);
+ hal_status = ath12k_dp_mon_parse_rx_dest(ar, 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);
@@ -2189,6 +2335,7 @@ ath12k_dp_mon_rx_parse_mon_status(struct ath12k *ar,
kfree(mon_mpdu);
}
+
return hal_status;
}
@@ -3375,7 +3522,7 @@ int ath12k_dp_mon_srng_process(struct ath12k *ar, int *budget,
ath12k_dp_mon_rx_memset_ppdu_info(ppdu_info);
while ((skb = __skb_dequeue(&skb_list))) {
- hal_status = ath12k_dp_mon_parse_rx_dest(ar, pmon, skb);
+ hal_status = ath12k_dp_mon_rx_parse_mon_status(ar, pmon, skb, napi);
if (hal_status != HAL_RX_MON_STATUS_PPDU_DONE) {
ppdu_info->ppdu_continuation = true;
dev_kfree_skb_any(skb);
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_DP_MON_H
@@ -9,6 +9,8 @@
#include "core.h"
+#define ATH12K_MON_RX_DOT11_OFFSET 5
+
enum dp_monitor_mode {
ATH12K_DP_TX_MONITOR_MODE,
ATH12K_DP_RX_MONITOR_MODE
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/ieee80211.h>
@@ -4439,6 +4439,7 @@ int ath12k_dp_rx_pdev_mon_attach(struct ath12k *ar)
pmon->mon_last_linkdesc_paddr = 0;
pmon->mon_last_buf_cookie = DP_RX_DESC_COOKIE_MAX + 1;
+ INIT_LIST_HEAD(&pmon->dp_rx_mon_mpdu_list);
spin_lock_init(&pmon->mon_lock);
return 0;
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_HAL_RX_H
@@ -111,11 +111,12 @@ enum hal_rx_mon_status {
HAL_RX_MON_STATUS_PPDU_DONE,
HAL_RX_MON_STATUS_BUF_DONE,
HAL_RX_MON_STATUS_BUF_ADDR,
+ HAL_RX_MON_STATUS_MPDU_START,
HAL_RX_MON_STATUS_MPDU_END,
HAL_RX_MON_STATUS_MSDU_END,
};
-#define HAL_RX_MAX_MPDU 256
+#define HAL_RX_MAX_MPDU 1024
#define HAL_RX_NUM_WORDS_PER_PPDU_BITMAP (HAL_RX_MAX_MPDU >> 5)
struct hal_rx_user_status {
@@ -509,6 +510,15 @@ struct hal_rx_mpdu_start {
__le32 rsvd2[16];
} __packed;
+struct hal_rx_msdu_end {
+ __le32 info0;
+ __le32 rsvd0[18];
+ __le32 info1;
+ __le32 rsvd1[10];
+ __le32 info2;
+ __le32 rsvd2;
+} __packed;
+
#define HAL_RX_PPDU_END_DURATION GENMASK(23, 0)
struct hal_rx_ppdu_end_duration {
__le32 rsvd0[9];