[PATCH v3 2/7] wifi: ath12k: Add extra TLV tag parsing support in monitor Rx path
Vasanthakumar Thiagarajan
quic_vthiagar at quicinc.com
Tue Jan 28 22:03:02 PST 2025
On 1/27/2025 5:10 PM, Karthikeyan Periyasamy wrote:
> From: P Praneesh <quic_ppranees at quicinc.com>
>
> Currently, the monitor Rx parser handler is inherited from the ath11k.
> However, the ath12k 802.11be hardware does not report the Rx TLV header
> in the MSDU data. Instead, the hardware reports those TLVs under the
> following TLV tags:
>
> 1. Buffer address
> 2. MPDU start
> 3. MPDU end
> 4. MSDU end
>
> Therefore, add support for parsing the above TLVs in the Rx monitor path
> and use this information for MSDU buffer and status updates.
>
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
>
> Signed-off-by: P Praneesh <quic_ppranees at quicinc.com>
> Signed-off-by: Karthikeyan Periyasamy <quic_periyasa at quicinc.com>
> Tested-by: Nicolas Escande <nico.escande at gmail.com>
> ---
> drivers/net/wireless/ath/ath12k/dp.h | 4 +-
> drivers/net/wireless/ath/ath12k/dp_mon.c | 157 ++++++++++++++++++++++-
> drivers/net/wireless/ath/ath12k/dp_mon.h | 4 +-
> drivers/net/wireless/ath/ath12k/dp_rx.c | 1 +
> drivers/net/wireless/ath/ath12k/hal_rx.h | 12 +-
> 5 files changed, 170 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h
> index f68bb78d4a11..27efd37f0955 100644
> --- a/drivers/net/wireless/ath/ath12k/dp.h
> +++ b/drivers/net/wireless/ath/ath12k/dp.h
> @@ -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
> diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c
> index 023715df1126..e9f53ac169b4 100644
> --- a/drivers/net/wireless/ath/ath12k/dp_mon.c
> +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c
> @@ -1678,7 +1678,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 */
> @@ -2121,6 +2121,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)
> @@ -2147,14 +2285,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));
>
> @@ -2175,9 +2319,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);
> @@ -2191,6 +2337,7 @@ ath12k_dp_mon_rx_parse_mon_status(struct ath12k *ar,
>
> kfree(mon_mpdu);
> }
> +
> return hal_status;
> }
>
> @@ -3377,7 +3524,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);
> diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.h b/drivers/net/wireless/ath/ath12k/dp_mon.h
> index e4368eb42aca..b039f6b9277c 100644
> --- a/drivers/net/wireless/ath/ath12k/dp_mon.h
> +++ b/drivers/net/wireless/ath/ath12k/dp_mon.h
> @@ -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
> diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
> index 95c9056642cf..44e47ec5b3ee 100644
> --- a/drivers/net/wireless/ath/ath12k/dp_rx.c
> +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
> @@ -4442,6 +4442,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;
> diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.h b/drivers/net/wireless/ath/ath12k/hal_rx.h
> index 6bdcd0867d86..6f10e4222ba6 100644
> --- a/drivers/net/wireless/ath/ath12k/hal_rx.h
> +++ b/drivers/net/wireless/ath/ath12k/hal_rx.h
> @@ -108,11 +108,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 {
> @@ -506,6 +507,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];
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan at oss.qualcomm.com>
More information about the ath12k
mailing list