Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  dp_mon.c   Sprache: C

 
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
 * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
 * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
 */


#include "dp_mon.h"
#include "debug.h"
#include "dp_rx.h"
#include "dp_tx.h"
#include "peer.h"

#define ATH12K_LE32_DEC_ENC(value, dec_bits, enc_bits) \
  u32_encode_bits(le32_get_bits(value, dec_bits), enc_bits)

#define ATH12K_LE64_DEC_ENC(value, dec_bits, enc_bits) \
  u32_encode_bits(le64_get_bits(value, dec_bits), enc_bits)

static void
ath12k_dp_mon_rx_handle_ofdma_info(const struct hal_rx_ppdu_end_user_stats *ppdu_end_user,
       struct hal_rx_user_status *rx_user_status)
{
 rx_user_status->ul_ofdma_user_v0_word0 =
  __le32_to_cpu(ppdu_end_user->usr_resp_ref);
 rx_user_status->ul_ofdma_user_v0_word1 =
  __le32_to_cpu(ppdu_end_user->usr_resp_ref_ext);
}

static void
ath12k_dp_mon_rx_populate_byte_count(const struct hal_rx_ppdu_end_user_stats *stats,
         void *ppduinfo,
         struct hal_rx_user_status *rx_user_status)
{
 rx_user_status->mpdu_ok_byte_count =
  le32_get_bits(stats->info7,
         HAL_RX_PPDU_END_USER_STATS_INFO7_MPDU_OK_BYTE_COUNT);
 rx_user_status->mpdu_err_byte_count =
  le32_get_bits(stats->info8,
         HAL_RX_PPDU_END_USER_STATS_INFO8_MPDU_ERR_BYTE_COUNT);
}

static void
ath12k_dp_mon_rx_populate_mu_user_info(const struct hal_rx_ppdu_end_user_stats *rx_tlv,
           struct hal_rx_mon_ppdu_info *ppdu_info,
           struct hal_rx_user_status *rx_user_status)
{
 rx_user_status->ast_index = ppdu_info->ast_index;
 rx_user_status->tid = ppdu_info->tid;
 rx_user_status->tcp_ack_msdu_count =
  ppdu_info->tcp_ack_msdu_count;
 rx_user_status->tcp_msdu_count =
  ppdu_info->tcp_msdu_count;
 rx_user_status->udp_msdu_count =
  ppdu_info->udp_msdu_count;
 rx_user_status->other_msdu_count =
  ppdu_info->other_msdu_count;
 rx_user_status->frame_control = ppdu_info->frame_control;
 rx_user_status->frame_control_info_valid =
  ppdu_info->frame_control_info_valid;
 rx_user_status->data_sequence_control_info_valid =
  ppdu_info->data_sequence_control_info_valid;
 rx_user_status->first_data_seq_ctrl =
  ppdu_info->first_data_seq_ctrl;
 rx_user_status->preamble_type = ppdu_info->preamble_type;
 rx_user_status->ht_flags = ppdu_info->ht_flags;
 rx_user_status->vht_flags = ppdu_info->vht_flags;
 rx_user_status->he_flags = ppdu_info->he_flags;
 rx_user_status->rs_flags = ppdu_info->rs_flags;

 rx_user_status->mpdu_cnt_fcs_ok =
  ppdu_info->num_mpdu_fcs_ok;
 rx_user_status->mpdu_cnt_fcs_err =
  ppdu_info->num_mpdu_fcs_err;
 memcpy(&rx_user_status->mpdu_fcs_ok_bitmap[0], &ppdu_info->mpdu_fcs_ok_bitmap[0],
        HAL_RX_NUM_WORDS_PER_PPDU_BITMAP *
        sizeof(ppdu_info->mpdu_fcs_ok_bitmap[0]));

 ath12k_dp_mon_rx_populate_byte_count(rx_tlv, ppdu_info, rx_user_status);
}

static void ath12k_dp_mon_parse_vht_sig_a(const struct hal_rx_vht_sig_a_info *vht_sig,
       struct hal_rx_mon_ppdu_info *ppdu_info)
{
 u32 nsts, info0, info1;
 u8 gi_setting;

 info0 = __le32_to_cpu(vht_sig->info0);
 info1 = __le32_to_cpu(vht_sig->info1);

 ppdu_info->ldpc = u32_get_bits(info1, HAL_RX_VHT_SIG_A_INFO_INFO1_SU_MU_CODING);
 ppdu_info->mcs = u32_get_bits(info1, HAL_RX_VHT_SIG_A_INFO_INFO1_MCS);
 gi_setting = u32_get_bits(info1, HAL_RX_VHT_SIG_A_INFO_INFO1_GI_SETTING);
 switch (gi_setting) {
 case HAL_RX_VHT_SIG_A_NORMAL_GI:
  ppdu_info->gi = HAL_RX_GI_0_8_US;
  break;
 case HAL_RX_VHT_SIG_A_SHORT_GI:
 case HAL_RX_VHT_SIG_A_SHORT_GI_AMBIGUITY:
  ppdu_info->gi = HAL_RX_GI_0_4_US;
  break;
 }

 ppdu_info->is_stbc = u32_get_bits(info0, HAL_RX_VHT_SIG_A_INFO_INFO0_STBC);
 nsts = u32_get_bits(info0, HAL_RX_VHT_SIG_A_INFO_INFO0_NSTS);
 if (ppdu_info->is_stbc && nsts > 0)
  nsts = ((nsts + 1) >> 1) - 1;

 ppdu_info->nss = u32_get_bits(nsts, VHT_SIG_SU_NSS_MASK);
 ppdu_info->bw = u32_get_bits(info0, HAL_RX_VHT_SIG_A_INFO_INFO0_BW);
 ppdu_info->beamformed = u32_get_bits(info1,
          HAL_RX_VHT_SIG_A_INFO_INFO1_BEAMFORMED);
 ppdu_info->vht_flag_values5 = u32_get_bits(info0,
         HAL_RX_VHT_SIG_A_INFO_INFO0_GROUP_ID);
 ppdu_info->vht_flag_values3[0] = (((ppdu_info->mcs) << 4) |
         ppdu_info->nss);
 ppdu_info->vht_flag_values2 = ppdu_info->bw;
 ppdu_info->vht_flag_values4 =
  u32_get_bits(info1, HAL_RX_VHT_SIG_A_INFO_INFO1_SU_MU_CODING);
}

static void ath12k_dp_mon_parse_ht_sig(const struct hal_rx_ht_sig_info *ht_sig,
           struct hal_rx_mon_ppdu_info *ppdu_info)
{
 u32 info0 = __le32_to_cpu(ht_sig->info0);
 u32 info1 = __le32_to_cpu(ht_sig->info1);

 ppdu_info->mcs = u32_get_bits(info0, HAL_RX_HT_SIG_INFO_INFO0_MCS);
 ppdu_info->bw = u32_get_bits(info0, HAL_RX_HT_SIG_INFO_INFO0_BW);
 ppdu_info->is_stbc = u32_get_bits(info1, HAL_RX_HT_SIG_INFO_INFO1_STBC);
 ppdu_info->ldpc = u32_get_bits(info1, HAL_RX_HT_SIG_INFO_INFO1_FEC_CODING);
 ppdu_info->gi = u32_get_bits(info1, HAL_RX_HT_SIG_INFO_INFO1_GI);
 ppdu_info->nss = (ppdu_info->mcs >> 3);
}

static void ath12k_dp_mon_parse_l_sig_b(const struct hal_rx_lsig_b_info *lsigb,
     struct hal_rx_mon_ppdu_info *ppdu_info)
{
 u32 info0 = __le32_to_cpu(lsigb->info0);
 u8 rate;

 rate = u32_get_bits(info0, HAL_RX_LSIG_B_INFO_INFO0_RATE);
 switch (rate) {
 case 1:
  rate = HAL_RX_LEGACY_RATE_1_MBPS;
  break;
 case 2:
 case 5:
  rate = HAL_RX_LEGACY_RATE_2_MBPS;
  break;
 case 3:
 case 6:
  rate = HAL_RX_LEGACY_RATE_5_5_MBPS;
  break;
 case 4:
 case 7:
  rate = HAL_RX_LEGACY_RATE_11_MBPS;
  break;
 default:
  rate = HAL_RX_LEGACY_RATE_INVALID;
 }

 ppdu_info->rate = rate;
 ppdu_info->cck_flag = 1;
}

static void ath12k_dp_mon_parse_l_sig_a(const struct hal_rx_lsig_a_info *lsiga,
     struct hal_rx_mon_ppdu_info *ppdu_info)
{
 u32 info0 = __le32_to_cpu(lsiga->info0);
 u8 rate;

 rate = u32_get_bits(info0, HAL_RX_LSIG_A_INFO_INFO0_RATE);
 switch (rate) {
 case 8:
  rate = HAL_RX_LEGACY_RATE_48_MBPS;
  break;
 case 9:
  rate = HAL_RX_LEGACY_RATE_24_MBPS;
  break;
 case 10:
  rate = HAL_RX_LEGACY_RATE_12_MBPS;
  break;
 case 11:
  rate = HAL_RX_LEGACY_RATE_6_MBPS;
  break;
 case 12:
  rate = HAL_RX_LEGACY_RATE_54_MBPS;
  break;
 case 13:
  rate = HAL_RX_LEGACY_RATE_36_MBPS;
  break;
 case 14:
  rate = HAL_RX_LEGACY_RATE_18_MBPS;
  break;
 case 15:
  rate = HAL_RX_LEGACY_RATE_9_MBPS;
  break;
 default:
  rate = HAL_RX_LEGACY_RATE_INVALID;
 }

 ppdu_info->rate = rate;
}

static void
ath12k_dp_mon_parse_he_sig_b2_ofdma(const struct hal_rx_he_sig_b2_ofdma_info *ofdma,
        struct hal_rx_mon_ppdu_info *ppdu_info)
{
 u32 info0, value;

 info0 = __le32_to_cpu(ofdma->info0);

 ppdu_info->he_data1 |= HE_MCS_KNOWN | HE_DCM_KNOWN | HE_CODING_KNOWN;

 /* HE-data2 */
 ppdu_info->he_data2 |= HE_TXBF_KNOWN;

 ppdu_info->mcs = u32_get_bits(info0, HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_MCS);
 value = ppdu_info->mcs << HE_TRANSMIT_MCS_SHIFT;
 ppdu_info->he_data3 |= value;

 value = u32_get_bits(info0, HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_DCM);
 value = value << HE_DCM_SHIFT;
 ppdu_info->he_data3 |= value;

 value = u32_get_bits(info0, HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_CODING);
 ppdu_info->ldpc = value;
 value = value << HE_CODING_SHIFT;
 ppdu_info->he_data3 |= value;

 /* HE-data4 */
 value = u32_get_bits(info0, HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_ID);
 value = value << HE_STA_ID_SHIFT;
 ppdu_info->he_data4 |= value;

 ppdu_info->nss = u32_get_bits(info0, HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_NSTS);
 ppdu_info->beamformed = u32_get_bits(info0,
          HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_TXBF);
}

static void
ath12k_dp_mon_parse_he_sig_b2_mu(const struct hal_rx_he_sig_b2_mu_info *he_sig_b2_mu,
     struct hal_rx_mon_ppdu_info *ppdu_info)
{
 u32 info0, value;

 info0 = __le32_to_cpu(he_sig_b2_mu->info0);

 ppdu_info->he_data1 |= HE_MCS_KNOWN | HE_CODING_KNOWN;

 ppdu_info->mcs = u32_get_bits(info0, HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_MCS);
 value = ppdu_info->mcs << HE_TRANSMIT_MCS_SHIFT;
 ppdu_info->he_data3 |= value;

 value = u32_get_bits(info0, HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_CODING);
 ppdu_info->ldpc = value;
 value = value << HE_CODING_SHIFT;
 ppdu_info->he_data3 |= value;

 value = u32_get_bits(info0, HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_ID);
 value = value << HE_STA_ID_SHIFT;
 ppdu_info->he_data4 |= value;

 ppdu_info->nss = u32_get_bits(info0, HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_NSTS);
}

static void
ath12k_dp_mon_parse_he_sig_b1_mu(const struct hal_rx_he_sig_b1_mu_info *he_sig_b1_mu,
     struct hal_rx_mon_ppdu_info *ppdu_info)
{
 u32 info0 = __le32_to_cpu(he_sig_b1_mu->info0);
 u16 ru_tones;

 ru_tones = u32_get_bits(info0,
    HAL_RX_HE_SIG_B1_MU_INFO_INFO0_RU_ALLOCATION);
 ppdu_info->ru_alloc = ath12k_he_ru_tones_to_nl80211_he_ru_alloc(ru_tones);
 ppdu_info->he_RU[0] = ru_tones;
}

static void
ath12k_dp_mon_parse_he_sig_mu(const struct hal_rx_he_sig_a_mu_dl_info *he_sig_a_mu_dl,
         struct hal_rx_mon_ppdu_info *ppdu_info)
{
 u32 info0, info1, value;
 u16 he_gi = 0, he_ltf = 0;

 info0 = __le32_to_cpu(he_sig_a_mu_dl->info0);
 info1 = __le32_to_cpu(he_sig_a_mu_dl->info1);

 ppdu_info->he_mu_flags = 1;

 ppdu_info->he_data1 = HE_MU_FORMAT_TYPE;
 ppdu_info->he_data1 |=
   HE_BSS_COLOR_KNOWN |
   HE_DL_UL_KNOWN |
   HE_LDPC_EXTRA_SYMBOL_KNOWN |
   HE_STBC_KNOWN |
   HE_DATA_BW_RU_KNOWN |
   HE_DOPPLER_KNOWN;

 ppdu_info->he_data2 =
   HE_GI_KNOWN |
   HE_LTF_SYMBOLS_KNOWN |
   HE_PRE_FEC_PADDING_KNOWN |
   HE_PE_DISAMBIGUITY_KNOWN |
   HE_TXOP_KNOWN |
   HE_MIDABLE_PERIODICITY_KNOWN;

 /* data3 */
 ppdu_info->he_data3 = u32_get_bits(info0, HAL_RX_HE_SIG_A_MU_DL_INFO0_BSS_COLOR);
 value = u32_get_bits(info0, HAL_RX_HE_SIG_A_MU_DL_INFO0_UL_FLAG);
 value = value << HE_DL_UL_SHIFT;
 ppdu_info->he_data3 |= value;

 value = u32_get_bits(info1, HAL_RX_HE_SIG_A_MU_DL_INFO1_LDPC_EXTRA);
 value = value << HE_LDPC_EXTRA_SYMBOL_SHIFT;
 ppdu_info->he_data3 |= value;

 value = u32_get_bits(info1, HAL_RX_HE_SIG_A_MU_DL_INFO1_STBC);
 value = value << HE_STBC_SHIFT;
 ppdu_info->he_data3 |= value;

 /* data4 */
 ppdu_info->he_data4 = u32_get_bits(info0,
        HAL_RX_HE_SIG_A_MU_DL_INFO0_SPATIAL_REUSE);
 ppdu_info->he_data4 = value;

 /* data5 */
 value = u32_get_bits(info0, HAL_RX_HE_SIG_A_MU_DL_INFO0_TRANSMIT_BW);
 ppdu_info->he_data5 = value;
 ppdu_info->bw = value;

 value = u32_get_bits(info0, HAL_RX_HE_SIG_A_MU_DL_INFO0_CP_LTF_SIZE);
 switch (value) {
 case 0:
  he_gi = HE_GI_0_8;
  he_ltf = HE_LTF_4_X;
  break;
 case 1:
  he_gi = HE_GI_0_8;
  he_ltf = HE_LTF_2_X;
  break;
 case 2:
  he_gi = HE_GI_1_6;
  he_ltf = HE_LTF_2_X;
  break;
 case 3:
  he_gi = HE_GI_3_2;
  he_ltf = HE_LTF_4_X;
  break;
 }

 ppdu_info->gi = he_gi;
 value = he_gi << HE_GI_SHIFT;
 ppdu_info->he_data5 |= value;

 value = he_ltf << HE_LTF_SIZE_SHIFT;
 ppdu_info->he_data5 |= value;

 value = u32_get_bits(info1, HAL_RX_HE_SIG_A_MU_DL_INFO1_NUM_LTF_SYMB);
 value = (value << HE_LTF_SYM_SHIFT);
 ppdu_info->he_data5 |= value;

 value = u32_get_bits(info1, HAL_RX_HE_SIG_A_MU_DL_INFO1_PKT_EXT_FACTOR);
 value = value << HE_PRE_FEC_PAD_SHIFT;
 ppdu_info->he_data5 |= value;

 value = u32_get_bits(info1, HAL_RX_HE_SIG_A_MU_DL_INFO1_PKT_EXT_PE_DISAM);
 value = value << HE_PE_DISAMBIGUITY_SHIFT;
 ppdu_info->he_data5 |= value;

 /*data6*/
 value = u32_get_bits(info0, HAL_RX_HE_SIG_A_MU_DL_INFO0_DOPPLER_INDICATION);
 value = value << HE_DOPPLER_SHIFT;
 ppdu_info->he_data6 |= value;

 value = u32_get_bits(info1, HAL_RX_HE_SIG_A_MU_DL_INFO1_TXOP_DURATION);
 value = value << HE_TXOP_SHIFT;
 ppdu_info->he_data6 |= value;

 /* HE-MU Flags */
 /* HE-MU-flags1 */
 ppdu_info->he_flags1 =
  HE_SIG_B_MCS_KNOWN |
  HE_SIG_B_DCM_KNOWN |
  HE_SIG_B_COMPRESSION_FLAG_1_KNOWN |
  HE_SIG_B_SYM_NUM_KNOWN |
  HE_RU_0_KNOWN;

 value = u32_get_bits(info0, HAL_RX_HE_SIG_A_MU_DL_INFO0_MCS_OF_SIGB);
 ppdu_info->he_flags1 |= value;
 value = u32_get_bits(info0, HAL_RX_HE_SIG_A_MU_DL_INFO0_DCM_OF_SIGB);
 value = value << HE_DCM_FLAG_1_SHIFT;
 ppdu_info->he_flags1 |= value;

 /* HE-MU-flags2 */
 ppdu_info->he_flags2 = HE_BW_KNOWN;

 value = u32_get_bits(info0, HAL_RX_HE_SIG_A_MU_DL_INFO0_TRANSMIT_BW);
 ppdu_info->he_flags2 |= value;
 value = u32_get_bits(info0, HAL_RX_HE_SIG_A_MU_DL_INFO0_COMP_MODE_SIGB);
 value = value << HE_SIG_B_COMPRESSION_FLAG_2_SHIFT;
 ppdu_info->he_flags2 |= value;
 value = u32_get_bits(info0, HAL_RX_HE_SIG_A_MU_DL_INFO0_NUM_SIGB_SYMB);
 value = value - 1;
 value = value << HE_NUM_SIG_B_SYMBOLS_SHIFT;
 ppdu_info->he_flags2 |= value;

 ppdu_info->is_stbc = info1 &
        HAL_RX_HE_SIG_A_MU_DL_INFO1_STBC;
}

static void ath12k_dp_mon_parse_he_sig_su(const struct hal_rx_he_sig_a_su_info *he_sig_a,
       struct hal_rx_mon_ppdu_info *ppdu_info)
{
 u32 info0, info1, value;
 u32 dcm;
 u8 he_dcm = 0, he_stbc = 0;
 u16 he_gi = 0, he_ltf = 0;

 ppdu_info->he_flags = 1;

 info0 = __le32_to_cpu(he_sig_a->info0);
 info1 = __le32_to_cpu(he_sig_a->info1);

 value = u32_get_bits(info0, HAL_RX_HE_SIG_A_SU_INFO_INFO0_FORMAT_IND);
 if (value == 0)
  ppdu_info->he_data1 = HE_TRIG_FORMAT_TYPE;
 else
  ppdu_info->he_data1 = HE_SU_FORMAT_TYPE;

 ppdu_info->he_data1 |=
   HE_BSS_COLOR_KNOWN |
   HE_BEAM_CHANGE_KNOWN |
   HE_DL_UL_KNOWN |
   HE_MCS_KNOWN |
   HE_DCM_KNOWN |
   HE_CODING_KNOWN |
   HE_LDPC_EXTRA_SYMBOL_KNOWN |
   HE_STBC_KNOWN |
   HE_DATA_BW_RU_KNOWN |
   HE_DOPPLER_KNOWN;

 ppdu_info->he_data2 |=
   HE_GI_KNOWN |
   HE_TXBF_KNOWN |
   HE_PE_DISAMBIGUITY_KNOWN |
   HE_TXOP_KNOWN |
   HE_LTF_SYMBOLS_KNOWN |
   HE_PRE_FEC_PADDING_KNOWN |
   HE_MIDABLE_PERIODICITY_KNOWN;

 ppdu_info->he_data3 = u32_get_bits(info0,
        HAL_RX_HE_SIG_A_SU_INFO_INFO0_BSS_COLOR);
 value = u32_get_bits(info0, HAL_RX_HE_SIG_A_SU_INFO_INFO0_BEAM_CHANGE);
 value = value << HE_BEAM_CHANGE_SHIFT;
 ppdu_info->he_data3 |= value;
 value = u32_get_bits(info0, HAL_RX_HE_SIG_A_SU_INFO_INFO0_DL_UL_FLAG);
 value = value << HE_DL_UL_SHIFT;
 ppdu_info->he_data3 |= value;

 value = u32_get_bits(info0, HAL_RX_HE_SIG_A_SU_INFO_INFO0_TRANSMIT_MCS);
 ppdu_info->mcs = value;
 value = value << HE_TRANSMIT_MCS_SHIFT;
 ppdu_info->he_data3 |= value;

 value = u32_get_bits(info0, HAL_RX_HE_SIG_A_SU_INFO_INFO0_DCM);
 he_dcm = value;
 value = value << HE_DCM_SHIFT;
 ppdu_info->he_data3 |= value;
 value = u32_get_bits(info1, HAL_RX_HE_SIG_A_SU_INFO_INFO1_CODING);
 value = value << HE_CODING_SHIFT;
 ppdu_info->he_data3 |= value;
 value = u32_get_bits(info1, HAL_RX_HE_SIG_A_SU_INFO_INFO1_LDPC_EXTRA);
 value = value << HE_LDPC_EXTRA_SYMBOL_SHIFT;
 ppdu_info->he_data3 |= value;
 value = u32_get_bits(info1, HAL_RX_HE_SIG_A_SU_INFO_INFO1_STBC);
 he_stbc = value;
 value = value << HE_STBC_SHIFT;
 ppdu_info->he_data3 |= value;

 /* data4 */
 ppdu_info->he_data4 = u32_get_bits(info0,
        HAL_RX_HE_SIG_A_SU_INFO_INFO0_SPATIAL_REUSE);

 /* data5 */
 value = u32_get_bits(info0,
        HAL_RX_HE_SIG_A_SU_INFO_INFO0_TRANSMIT_BW);
 ppdu_info->he_data5 = value;
 ppdu_info->bw = value;
 value = u32_get_bits(info0, HAL_RX_HE_SIG_A_SU_INFO_INFO0_CP_LTF_SIZE);
 switch (value) {
 case 0:
  he_gi = HE_GI_0_8;
  he_ltf = HE_LTF_1_X;
  break;
 case 1:
  he_gi = HE_GI_0_8;
  he_ltf = HE_LTF_2_X;
  break;
 case 2:
  he_gi = HE_GI_1_6;
  he_ltf = HE_LTF_2_X;
  break;
 case 3:
  if (he_dcm && he_stbc) {
   he_gi = HE_GI_0_8;
   he_ltf = HE_LTF_4_X;
  } else {
   he_gi = HE_GI_3_2;
   he_ltf = HE_LTF_4_X;
  }
  break;
 }
 ppdu_info->gi = he_gi;
 value = he_gi << HE_GI_SHIFT;
 ppdu_info->he_data5 |= value;
 value = he_ltf << HE_LTF_SIZE_SHIFT;
 ppdu_info->ltf_size = he_ltf;
 ppdu_info->he_data5 |= value;

 value = u32_get_bits(info0, HAL_RX_HE_SIG_A_SU_INFO_INFO0_NSTS);
 value = (value << HE_LTF_SYM_SHIFT);
 ppdu_info->he_data5 |= value;

 value = u32_get_bits(info1, HAL_RX_HE_SIG_A_SU_INFO_INFO1_PKT_EXT_FACTOR);
 value = value << HE_PRE_FEC_PAD_SHIFT;
 ppdu_info->he_data5 |= value;

 value = u32_get_bits(info1, HAL_RX_HE_SIG_A_SU_INFO_INFO1_TXBF);
 value = value << HE_TXBF_SHIFT;
 ppdu_info->he_data5 |= value;
 value = u32_get_bits(info1, HAL_RX_HE_SIG_A_SU_INFO_INFO1_PKT_EXT_PE_DISAM);
 value = value << HE_PE_DISAMBIGUITY_SHIFT;
 ppdu_info->he_data5 |= value;

 /* data6 */
 value = u32_get_bits(info0, HAL_RX_HE_SIG_A_SU_INFO_INFO0_NSTS);
 value++;
 ppdu_info->he_data6 = value;
 value = u32_get_bits(info1, HAL_RX_HE_SIG_A_SU_INFO_INFO1_DOPPLER_IND);
 value = value << HE_DOPPLER_SHIFT;
 ppdu_info->he_data6 |= value;
 value = u32_get_bits(info1, HAL_RX_HE_SIG_A_SU_INFO_INFO1_TXOP_DURATION);
 value = value << HE_TXOP_SHIFT;
 ppdu_info->he_data6 |= value;

 ppdu_info->mcs =
  u32_get_bits(info0, HAL_RX_HE_SIG_A_SU_INFO_INFO0_TRANSMIT_MCS);
 ppdu_info->bw =
  u32_get_bits(info0, HAL_RX_HE_SIG_A_SU_INFO_INFO0_TRANSMIT_BW);
 ppdu_info->ldpc = u32_get_bits(info1, HAL_RX_HE_SIG_A_SU_INFO_INFO1_CODING);
 ppdu_info->is_stbc = u32_get_bits(info1, HAL_RX_HE_SIG_A_SU_INFO_INFO1_STBC);
 ppdu_info->beamformed = u32_get_bits(info1, HAL_RX_HE_SIG_A_SU_INFO_INFO1_TXBF);
 dcm = u32_get_bits(info0, HAL_RX_HE_SIG_A_SU_INFO_INFO0_DCM);
 ppdu_info->nss = u32_get_bits(info0, HAL_RX_HE_SIG_A_SU_INFO_INFO0_NSTS);
 ppdu_info->dcm = dcm;
}

static void
ath12k_dp_mon_hal_rx_parse_u_sig_cmn(const struct hal_mon_usig_cmn *cmn,
         struct hal_rx_mon_ppdu_info *ppdu_info)
{
 u32 common;

 ppdu_info->u_sig_info.bw = le32_get_bits(cmn->info0,
       HAL_RX_USIG_CMN_INFO0_BW);
 ppdu_info->u_sig_info.ul_dl = le32_get_bits(cmn->info0,
          HAL_RX_USIG_CMN_INFO0_UL_DL);

 common = __le32_to_cpu(ppdu_info->u_sig_info.usig.common);
 common |= IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER_KNOWN |
    IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_KNOWN |
    IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL_KNOWN |
    IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR_KNOWN |
    IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP_KNOWN |
    ATH12K_LE32_DEC_ENC(cmn->info0,
          HAL_RX_USIG_CMN_INFO0_PHY_VERSION,
          IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER) |
    u32_encode_bits(ppdu_info->u_sig_info.bw,
      IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW) |
    u32_encode_bits(ppdu_info->u_sig_info.ul_dl,
      IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL) |
    ATH12K_LE32_DEC_ENC(cmn->info0,
          HAL_RX_USIG_CMN_INFO0_BSS_COLOR,
          IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR) |
    ATH12K_LE32_DEC_ENC(cmn->info0,
          HAL_RX_USIG_CMN_INFO0_TXOP,
          IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP);
 ppdu_info->u_sig_info.usig.common = cpu_to_le32(common);

 switch (ppdu_info->u_sig_info.bw) {
 default:
  fallthrough;
 case HAL_EHT_BW_20:
  ppdu_info->bw = HAL_RX_BW_20MHZ;
  break;
 case HAL_EHT_BW_40:
  ppdu_info->bw = HAL_RX_BW_40MHZ;
  break;
 case HAL_EHT_BW_80:
  ppdu_info->bw = HAL_RX_BW_80MHZ;
  break;
 case HAL_EHT_BW_160:
  ppdu_info->bw = HAL_RX_BW_160MHZ;
  break;
 case HAL_EHT_BW_320_1:
 case HAL_EHT_BW_320_2:
  ppdu_info->bw = HAL_RX_BW_320MHZ;
  break;
 }
}

static void
ath12k_dp_mon_hal_rx_parse_u_sig_tb(const struct hal_mon_usig_tb *usig_tb,
        struct hal_rx_mon_ppdu_info *ppdu_info)
{
 struct ieee80211_radiotap_eht_usig *usig = &ppdu_info->u_sig_info.usig;
 enum ieee80211_radiotap_eht_usig_tb spatial_reuse1, spatial_reuse2;
 u32 common, value, mask;

 spatial_reuse1 = IEEE80211_RADIOTAP_EHT_USIG2_TB_B3_B6_SPATIAL_REUSE_1;
 spatial_reuse2 = IEEE80211_RADIOTAP_EHT_USIG2_TB_B7_B10_SPATIAL_REUSE_2;

 common = __le32_to_cpu(usig->common);
 value = __le32_to_cpu(usig->value);
 mask = __le32_to_cpu(usig->mask);

 ppdu_info->u_sig_info.ppdu_type_comp_mode =
    le32_get_bits(usig_tb->info0,
           HAL_RX_USIG_TB_INFO0_PPDU_TYPE_COMP_MODE);

 common |= ATH12K_LE32_DEC_ENC(usig_tb->info0,
          HAL_RX_USIG_TB_INFO0_RX_INTEG_CHECK_PASS,
          IEEE80211_RADIOTAP_EHT_USIG_COMMON_BAD_USIG_CRC);

 value |= IEEE80211_RADIOTAP_EHT_USIG1_TB_B20_B25_DISREGARD |
   u32_encode_bits(ppdu_info->u_sig_info.ppdu_type_comp_mode,
     IEEE80211_RADIOTAP_EHT_USIG2_TB_B0_B1_PPDU_TYPE) |
   IEEE80211_RADIOTAP_EHT_USIG2_TB_B2_VALIDATE |
   ATH12K_LE32_DEC_ENC(usig_tb->info0,
         HAL_RX_USIG_TB_INFO0_SPATIAL_REUSE_1,
         spatial_reuse1) |
   ATH12K_LE32_DEC_ENC(usig_tb->info0,
         HAL_RX_USIG_TB_INFO0_SPATIAL_REUSE_2,
         spatial_reuse2) |
   IEEE80211_RADIOTAP_EHT_USIG2_TB_B11_B15_DISREGARD |
   ATH12K_LE32_DEC_ENC(usig_tb->info0,
         HAL_RX_USIG_TB_INFO0_CRC,
         IEEE80211_RADIOTAP_EHT_USIG2_TB_B16_B19_CRC) |
   ATH12K_LE32_DEC_ENC(usig_tb->info0,
         HAL_RX_USIG_TB_INFO0_TAIL,
         IEEE80211_RADIOTAP_EHT_USIG2_TB_B20_B25_TAIL);

 mask |= IEEE80211_RADIOTAP_EHT_USIG1_TB_B20_B25_DISREGARD |
  IEEE80211_RADIOTAP_EHT_USIG2_TB_B0_B1_PPDU_TYPE |
  IEEE80211_RADIOTAP_EHT_USIG2_TB_B2_VALIDATE |
  spatial_reuse1 | spatial_reuse2 |
  IEEE80211_RADIOTAP_EHT_USIG2_TB_B11_B15_DISREGARD |
  IEEE80211_RADIOTAP_EHT_USIG2_TB_B16_B19_CRC |
  IEEE80211_RADIOTAP_EHT_USIG2_TB_B20_B25_TAIL;

 usig->common = cpu_to_le32(common);
 usig->value = cpu_to_le32(value);
 usig->mask = cpu_to_le32(mask);
}

static void
ath12k_dp_mon_hal_rx_parse_u_sig_mu(const struct hal_mon_usig_mu *usig_mu,
        struct hal_rx_mon_ppdu_info *ppdu_info)
{
 struct ieee80211_radiotap_eht_usig *usig = &ppdu_info->u_sig_info.usig;
 enum ieee80211_radiotap_eht_usig_mu sig_symb, punc;
 u32 common, value, mask;

 sig_symb = IEEE80211_RADIOTAP_EHT_USIG2_MU_B11_B15_EHT_SIG_SYMBOLS;
 punc = IEEE80211_RADIOTAP_EHT_USIG2_MU_B3_B7_PUNCTURED_INFO;

 common = __le32_to_cpu(usig->common);
 value = __le32_to_cpu(usig->value);
 mask = __le32_to_cpu(usig->mask);

 ppdu_info->u_sig_info.ppdu_type_comp_mode =
    le32_get_bits(usig_mu->info0,
           HAL_RX_USIG_MU_INFO0_PPDU_TYPE_COMP_MODE);
 ppdu_info->u_sig_info.eht_sig_mcs =
    le32_get_bits(usig_mu->info0,
           HAL_RX_USIG_MU_INFO0_EHT_SIG_MCS);
 ppdu_info->u_sig_info.num_eht_sig_sym =
    le32_get_bits(usig_mu->info0,
           HAL_RX_USIG_MU_INFO0_NUM_EHT_SIG_SYM);

 common |= ATH12K_LE32_DEC_ENC(usig_mu->info0,
          HAL_RX_USIG_MU_INFO0_RX_INTEG_CHECK_PASS,
          IEEE80211_RADIOTAP_EHT_USIG_COMMON_BAD_USIG_CRC);

 value |= IEEE80211_RADIOTAP_EHT_USIG1_MU_B20_B24_DISREGARD |
   IEEE80211_RADIOTAP_EHT_USIG1_MU_B25_VALIDATE |
   u32_encode_bits(ppdu_info->u_sig_info.ppdu_type_comp_mode,
     IEEE80211_RADIOTAP_EHT_USIG2_MU_B0_B1_PPDU_TYPE) |
   IEEE80211_RADIOTAP_EHT_USIG2_MU_B2_VALIDATE |
   ATH12K_LE32_DEC_ENC(usig_mu->info0,
         HAL_RX_USIG_MU_INFO0_PUNC_CH_INFO,
         punc) |
   IEEE80211_RADIOTAP_EHT_USIG2_MU_B8_VALIDATE |
   u32_encode_bits(ppdu_info->u_sig_info.eht_sig_mcs,
     IEEE80211_RADIOTAP_EHT_USIG2_MU_B9_B10_SIG_MCS) |
   u32_encode_bits(ppdu_info->u_sig_info.num_eht_sig_sym,
     sig_symb) |
   ATH12K_LE32_DEC_ENC(usig_mu->info0,
         HAL_RX_USIG_MU_INFO0_CRC,
         IEEE80211_RADIOTAP_EHT_USIG2_MU_B16_B19_CRC) |
   ATH12K_LE32_DEC_ENC(usig_mu->info0,
         HAL_RX_USIG_MU_INFO0_TAIL,
         IEEE80211_RADIOTAP_EHT_USIG2_MU_B20_B25_TAIL);

 mask |= IEEE80211_RADIOTAP_EHT_USIG1_MU_B20_B24_DISREGARD |
  IEEE80211_RADIOTAP_EHT_USIG1_MU_B25_VALIDATE |
  IEEE80211_RADIOTAP_EHT_USIG2_MU_B0_B1_PPDU_TYPE |
  IEEE80211_RADIOTAP_EHT_USIG2_MU_B2_VALIDATE |
  punc |
  IEEE80211_RADIOTAP_EHT_USIG2_MU_B8_VALIDATE |
  IEEE80211_RADIOTAP_EHT_USIG2_MU_B9_B10_SIG_MCS |
  sig_symb |
  IEEE80211_RADIOTAP_EHT_USIG2_MU_B16_B19_CRC |
  IEEE80211_RADIOTAP_EHT_USIG2_MU_B20_B25_TAIL;

 usig->common = cpu_to_le32(common);
 usig->value = cpu_to_le32(value);
 usig->mask = cpu_to_le32(mask);
}

static void
ath12k_dp_mon_hal_rx_parse_u_sig_hdr(const struct hal_mon_usig_hdr *usig,
         struct hal_rx_mon_ppdu_info *ppdu_info)
{
 u8 comp_mode;

 ppdu_info->eht_usig = true;

 ath12k_dp_mon_hal_rx_parse_u_sig_cmn(&usig->cmn, ppdu_info);

 comp_mode = le32_get_bits(usig->non_cmn.mu.info0,
      HAL_RX_USIG_MU_INFO0_PPDU_TYPE_COMP_MODE);

 if (comp_mode == 0 && ppdu_info->u_sig_info.ul_dl)
  ath12k_dp_mon_hal_rx_parse_u_sig_tb(&usig->non_cmn.tb, ppdu_info);
 else
  ath12k_dp_mon_hal_rx_parse_u_sig_mu(&usig->non_cmn.mu, ppdu_info);
}

static void
ath12k_dp_mon_hal_aggr_tlv(struct hal_rx_mon_ppdu_info *ppdu_info,
      u16 tlv_len, const void *tlv_data)
{
 if (tlv_len <= HAL_RX_MON_MAX_AGGR_SIZE - ppdu_info->tlv_aggr.cur_len) {
  memcpy(ppdu_info->tlv_aggr.buf + ppdu_info->tlv_aggr.cur_len,
         tlv_data, tlv_len);
  ppdu_info->tlv_aggr.cur_len += tlv_len;
 }
}

static inline bool
ath12k_dp_mon_hal_rx_is_frame_type_ndp(const struct hal_rx_u_sig_info *usig_info)
{
 if (usig_info->ppdu_type_comp_mode == 1 &&
     usig_info->eht_sig_mcs == 0 &&
     usig_info->num_eht_sig_sym == 0)
  return true;

 return false;
}

static inline bool
ath12k_dp_mon_hal_rx_is_non_ofdma(const struct hal_rx_u_sig_info *usig_info)
{
 u32 ppdu_type_comp_mode = usig_info->ppdu_type_comp_mode;
 u32 ul_dl = usig_info->ul_dl;

 if ((ppdu_type_comp_mode == HAL_RX_RECEPTION_TYPE_MU_MIMO && ul_dl == 0) ||
     (ppdu_type_comp_mode == HAL_RX_RECEPTION_TYPE_MU_OFDMA && ul_dl == 0) ||
     (ppdu_type_comp_mode == HAL_RX_RECEPTION_TYPE_MU_MIMO  && ul_dl == 1))
  return true;

 return false;
}

static inline bool
ath12k_dp_mon_hal_rx_is_ofdma(const struct hal_rx_u_sig_info *usig_info)
{
 if (usig_info->ppdu_type_comp_mode == 0 && usig_info->ul_dl == 0)
  return true;

 return false;
}

static void
ath12k_dp_mon_hal_rx_parse_eht_sig_ndp(const struct hal_eht_sig_ndp_cmn_eb *eht_sig_ndp,
           struct hal_rx_mon_ppdu_info *ppdu_info)
{
 struct hal_rx_radiotap_eht *eht = &ppdu_info->eht_info.eht;
 u32 known, data;

 known = __le32_to_cpu(eht->known);
 known |= IEEE80211_RADIOTAP_EHT_KNOWN_SPATIAL_REUSE |
   IEEE80211_RADIOTAP_EHT_KNOWN_EHT_LTF |
   IEEE80211_RADIOTAP_EHT_KNOWN_NSS_S |
   IEEE80211_RADIOTAP_EHT_KNOWN_BEAMFORMED_S |
   IEEE80211_RADIOTAP_EHT_KNOWN_DISREGARD_S |
   IEEE80211_RADIOTAP_EHT_KNOWN_CRC1 |
   IEEE80211_RADIOTAP_EHT_KNOWN_TAIL1;
 eht->known = cpu_to_le32(known);

 data = __le32_to_cpu(eht->data[0]);
 data |= ATH12K_LE32_DEC_ENC(eht_sig_ndp->info0,
        HAL_RX_EHT_SIG_NDP_CMN_INFO0_SPATIAL_REUSE,
        IEEE80211_RADIOTAP_EHT_DATA0_SPATIAL_REUSE);
 /* GI and LTF size are separately indicated in radiotap header
 * and hence will be parsed from other TLV
 */

 data |= ATH12K_LE32_DEC_ENC(eht_sig_ndp->info0,
        HAL_RX_EHT_SIG_NDP_CMN_INFO0_NUM_LTF_SYM,
        IEEE80211_RADIOTAP_EHT_DATA0_EHT_LTF);

 data |= ATH12K_LE32_DEC_ENC(eht_sig_ndp->info0,
        HAL_RX_EHT_SIG_NDP_CMN_INFO0_CRC,
        IEEE80211_RADIOTAP_EHT_DATA0_CRC1_O);

 data |= ATH12K_LE32_DEC_ENC(eht_sig_ndp->info0,
        HAL_RX_EHT_SIG_NDP_CMN_INFO0_DISREGARD,
        IEEE80211_RADIOTAP_EHT_DATA0_DISREGARD_S);
 eht->data[0] = cpu_to_le32(data);

 data = __le32_to_cpu(eht->data[7]);
 data |= ATH12K_LE32_DEC_ENC(eht_sig_ndp->info0,
        HAL_RX_EHT_SIG_NDP_CMN_INFO0_NSS,
        IEEE80211_RADIOTAP_EHT_DATA7_NSS_S);

 data |= ATH12K_LE32_DEC_ENC(eht_sig_ndp->info0,
        HAL_RX_EHT_SIG_NDP_CMN_INFO0_BEAMFORMED,
        IEEE80211_RADIOTAP_EHT_DATA7_BEAMFORMED_S);
 eht->data[7] = cpu_to_le32(data);
}

static void
ath12k_dp_mon_hal_rx_parse_usig_overflow(const struct hal_eht_sig_usig_overflow *ovflow,
      struct hal_rx_mon_ppdu_info *ppdu_info)
{
 struct hal_rx_radiotap_eht *eht = &ppdu_info->eht_info.eht;
 u32 known, data;

 known = __le32_to_cpu(eht->known);
 known |= IEEE80211_RADIOTAP_EHT_KNOWN_SPATIAL_REUSE |
   IEEE80211_RADIOTAP_EHT_KNOWN_EHT_LTF |
   IEEE80211_RADIOTAP_EHT_KNOWN_LDPC_EXTRA_SYM_OM |
   IEEE80211_RADIOTAP_EHT_KNOWN_PRE_PADD_FACOR_OM |
   IEEE80211_RADIOTAP_EHT_KNOWN_PE_DISAMBIGUITY_OM |
   IEEE80211_RADIOTAP_EHT_KNOWN_DISREGARD_O;
 eht->known = cpu_to_le32(known);

 data = __le32_to_cpu(eht->data[0]);
 data |= ATH12K_LE32_DEC_ENC(ovflow->info0,
        HAL_RX_EHT_SIG_OVERFLOW_INFO0_SPATIAL_REUSE,
        IEEE80211_RADIOTAP_EHT_DATA0_SPATIAL_REUSE);

 /* GI and LTF size are separately indicated in radiotap header
 * and hence will be parsed from other TLV
 */

 data |= ATH12K_LE32_DEC_ENC(ovflow->info0,
        HAL_RX_EHT_SIG_OVERFLOW_INFO0_NUM_LTF_SYM,
        IEEE80211_RADIOTAP_EHT_DATA0_EHT_LTF);

 data |= ATH12K_LE32_DEC_ENC(ovflow->info0,
        HAL_RX_EHT_SIG_OVERFLOW_INFO0_LDPC_EXTA_SYM,
        IEEE80211_RADIOTAP_EHT_DATA0_LDPC_EXTRA_SYM_OM);

 data |= ATH12K_LE32_DEC_ENC(ovflow->info0,
        HAL_RX_EHT_SIG_OVERFLOW_INFO0_PRE_FEC_PAD_FACTOR,
        IEEE80211_RADIOTAP_EHT_DATA0_PRE_PADD_FACOR_OM);

 data |= ATH12K_LE32_DEC_ENC(ovflow->info0,
        HAL_RX_EHT_SIG_OVERFLOW_INFO0_DISAMBIGUITY,
        IEEE80211_RADIOTAP_EHT_DATA0_PE_DISAMBIGUITY_OM);

 data |= ATH12K_LE32_DEC_ENC(ovflow->info0,
        HAL_RX_EHT_SIG_OVERFLOW_INFO0_DISREGARD,
        IEEE80211_RADIOTAP_EHT_DATA0_DISREGARD_O);
 eht->data[0] = cpu_to_le32(data);
}

static void
ath12k_dp_mon_hal_rx_parse_non_ofdma_users(const struct hal_eht_sig_non_ofdma_cmn_eb *eb,
        struct hal_rx_mon_ppdu_info *ppdu_info)
{
 struct hal_rx_radiotap_eht *eht = &ppdu_info->eht_info.eht;
 u32 known, data;

 known = __le32_to_cpu(eht->known);
 known |= IEEE80211_RADIOTAP_EHT_KNOWN_NR_NON_OFDMA_USERS_M;
 eht->known = cpu_to_le32(known);

 data = __le32_to_cpu(eht->data[7]);
 data |= ATH12K_LE32_DEC_ENC(eb->info0,
        HAL_RX_EHT_SIG_NON_OFDMA_INFO0_NUM_USERS,
        IEEE80211_RADIOTAP_EHT_DATA7_NUM_OF_NON_OFDMA_USERS);
 eht->data[7] = cpu_to_le32(data);
}

static void
ath12k_dp_mon_hal_rx_parse_eht_mumimo_user(const struct hal_eht_sig_mu_mimo *user,
        struct hal_rx_mon_ppdu_info *ppdu_info)
{
 struct hal_rx_eht_info *eht_info = &ppdu_info->eht_info;
 u32 user_idx;

 if (eht_info->num_user_info >= ARRAY_SIZE(eht_info->user_info))
  return;

 user_idx = eht_info->num_user_info++;

 eht_info->user_info[user_idx] |=
  IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID_KNOWN |
  IEEE80211_RADIOTAP_EHT_USER_INFO_MCS_KNOWN |
  IEEE80211_RADIOTAP_EHT_USER_INFO_CODING_KNOWN |
  IEEE80211_RADIOTAP_EHT_USER_INFO_SPATIAL_CONFIG_KNOWN_M |
  ATH12K_LE32_DEC_ENC(user->info0,
        HAL_RX_EHT_SIG_MUMIMO_USER_INFO0_STA_ID,
        IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID) |
  ATH12K_LE32_DEC_ENC(user->info0,
        HAL_RX_EHT_SIG_MUMIMO_USER_INFO0_CODING,
        IEEE80211_RADIOTAP_EHT_USER_INFO_CODING) |
  ATH12K_LE32_DEC_ENC(user->info0,
        HAL_RX_EHT_SIG_MUMIMO_USER_INFO0_MCS,
        IEEE80211_RADIOTAP_EHT_USER_INFO_MCS) |
  ATH12K_LE32_DEC_ENC(user->info0,
        HAL_RX_EHT_SIG_MUMIMO_USER_INFO0_SPATIAL_CODING,
        IEEE80211_RADIOTAP_EHT_USER_INFO_SPATIAL_CONFIG_M);

 ppdu_info->mcs = le32_get_bits(user->info0,
           HAL_RX_EHT_SIG_MUMIMO_USER_INFO0_MCS);
}

static void
ath12k_dp_mon_hal_rx_parse_eht_non_mumimo_user(const struct hal_eht_sig_non_mu_mimo *user,
            struct hal_rx_mon_ppdu_info *ppdu_info)
{
 struct hal_rx_eht_info *eht_info = &ppdu_info->eht_info;
 u32 user_idx;

 if (eht_info->num_user_info >= ARRAY_SIZE(eht_info->user_info))
  return;

 user_idx = eht_info->num_user_info++;

 eht_info->user_info[user_idx] |=
  IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID_KNOWN |
  IEEE80211_RADIOTAP_EHT_USER_INFO_MCS_KNOWN |
  IEEE80211_RADIOTAP_EHT_USER_INFO_CODING_KNOWN |
  IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_KNOWN_O |
  IEEE80211_RADIOTAP_EHT_USER_INFO_BEAMFORMING_KNOWN_O |
  ATH12K_LE32_DEC_ENC(user->info0,
        HAL_RX_EHT_SIG_NON_MUMIMO_USER_INFO0_STA_ID,
        IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID) |
  ATH12K_LE32_DEC_ENC(user->info0,
        HAL_RX_EHT_SIG_NON_MUMIMO_USER_INFO0_CODING,
        IEEE80211_RADIOTAP_EHT_USER_INFO_CODING) |
  ATH12K_LE32_DEC_ENC(user->info0,
        HAL_RX_EHT_SIG_NON_MUMIMO_USER_INFO0_MCS,
        IEEE80211_RADIOTAP_EHT_USER_INFO_MCS) |
  ATH12K_LE32_DEC_ENC(user->info0,
        HAL_RX_EHT_SIG_NON_MUMIMO_USER_INFO0_NSS,
        IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_O) |
  ATH12K_LE32_DEC_ENC(user->info0,
        HAL_RX_EHT_SIG_NON_MUMIMO_USER_INFO0_BEAMFORMED,
        IEEE80211_RADIOTAP_EHT_USER_INFO_BEAMFORMING_O);

 ppdu_info->mcs = le32_get_bits(user->info0,
           HAL_RX_EHT_SIG_NON_MUMIMO_USER_INFO0_MCS);

 ppdu_info->nss = le32_get_bits(user->info0,
           HAL_RX_EHT_SIG_NON_MUMIMO_USER_INFO0_NSS) + 1;
}

static inline bool
ath12k_dp_mon_hal_rx_is_mu_mimo_user(const struct hal_rx_u_sig_info *usig_info)
{
 if (usig_info->ppdu_type_comp_mode == HAL_RX_RECEPTION_TYPE_SU &&
     usig_info->ul_dl == 1)
  return true;

 return false;
}

static void
ath12k_dp_mon_hal_rx_parse_eht_sig_non_ofdma(const void *tlv,
          struct hal_rx_mon_ppdu_info *ppdu_info)
{
 const struct hal_eht_sig_non_ofdma_cmn_eb *eb = tlv;

 ath12k_dp_mon_hal_rx_parse_usig_overflow(tlv, ppdu_info);
 ath12k_dp_mon_hal_rx_parse_non_ofdma_users(eb, ppdu_info);

 if (ath12k_dp_mon_hal_rx_is_mu_mimo_user(&ppdu_info->u_sig_info))
  ath12k_dp_mon_hal_rx_parse_eht_mumimo_user(&eb->user_field.mu_mimo,
          ppdu_info);
 else
  ath12k_dp_mon_hal_rx_parse_eht_non_mumimo_user(&eb->user_field.n_mu_mimo,
              ppdu_info);
}

static void
ath12k_dp_mon_hal_rx_parse_ru_allocation(const struct hal_eht_sig_ofdma_cmn_eb *eb,
      struct hal_rx_mon_ppdu_info *ppdu_info)
{
 const struct hal_eht_sig_ofdma_cmn_eb1 *ofdma_cmn_eb1 = &eb->eb1;
 const struct hal_eht_sig_ofdma_cmn_eb2 *ofdma_cmn_eb2 = &eb->eb2;
 struct hal_rx_radiotap_eht *eht = &ppdu_info->eht_info.eht;
 enum ieee80211_radiotap_eht_data ru_123, ru_124, ru_125, ru_126;
 enum ieee80211_radiotap_eht_data ru_121, ru_122, ru_112, ru_111;
 u32 data;

 ru_123 = IEEE80211_RADIOTAP_EHT_DATA4_RU_ALLOC_CC_1_2_3;
 ru_124 = IEEE80211_RADIOTAP_EHT_DATA5_RU_ALLOC_CC_1_2_4;
 ru_125 = IEEE80211_RADIOTAP_EHT_DATA5_RU_ALLOC_CC_1_2_5;
 ru_126 = IEEE80211_RADIOTAP_EHT_DATA6_RU_ALLOC_CC_1_2_6;
 ru_121 = IEEE80211_RADIOTAP_EHT_DATA3_RU_ALLOC_CC_1_2_1;
 ru_122 = IEEE80211_RADIOTAP_EHT_DATA3_RU_ALLOC_CC_1_2_2;
 ru_112 = IEEE80211_RADIOTAP_EHT_DATA2_RU_ALLOC_CC_1_1_2;
 ru_111 = IEEE80211_RADIOTAP_EHT_DATA1_RU_ALLOC_CC_1_1_1;

 switch (ppdu_info->u_sig_info.bw) {
 case HAL_EHT_BW_320_2:
 case HAL_EHT_BW_320_1:
  data = __le32_to_cpu(eht->data[4]);
  /* CC1 2::3 */
  data |= IEEE80211_RADIOTAP_EHT_DATA4_RU_ALLOC_CC_1_2_3_KNOWN |
   ATH12K_LE64_DEC_ENC(ofdma_cmn_eb2->info0,
         HAL_RX_EHT_SIG_OFDMA_EB2_RU_ALLOC_2_3,
         ru_123);
  eht->data[4] = cpu_to_le32(data);

  data = __le32_to_cpu(eht->data[5]);
  /* CC1 2::4 */
  data |= IEEE80211_RADIOTAP_EHT_DATA5_RU_ALLOC_CC_1_2_4_KNOWN |
   ATH12K_LE64_DEC_ENC(ofdma_cmn_eb2->info0,
         HAL_RX_EHT_SIG_OFDMA_EB2_RU_ALLOC_2_4,
         ru_124);

  /* CC1 2::5 */
  data |= IEEE80211_RADIOTAP_EHT_DATA5_RU_ALLOC_CC_1_2_5_KNOWN |
   ATH12K_LE64_DEC_ENC(ofdma_cmn_eb2->info0,
         HAL_RX_EHT_SIG_OFDMA_EB2_RU_ALLOC_2_5,
         ru_125);
  eht->data[5] = cpu_to_le32(data);

  data = __le32_to_cpu(eht->data[6]);
  /* CC1 2::6 */
  data |= IEEE80211_RADIOTAP_EHT_DATA6_RU_ALLOC_CC_1_2_6_KNOWN |
   ATH12K_LE64_DEC_ENC(ofdma_cmn_eb2->info0,
         HAL_RX_EHT_SIG_OFDMA_EB2_RU_ALLOC_2_6,
         ru_126);
  eht->data[6] = cpu_to_le32(data);

  fallthrough;
 case HAL_EHT_BW_160:
  data = __le32_to_cpu(eht->data[3]);
  /* CC1 2::1 */
  data |= IEEE80211_RADIOTAP_EHT_DATA3_RU_ALLOC_CC_1_2_1_KNOWN |
   ATH12K_LE64_DEC_ENC(ofdma_cmn_eb2->info0,
         HAL_RX_EHT_SIG_OFDMA_EB2_RU_ALLOC_2_1,
         ru_121);
  /* CC1 2::2 */
  data |= IEEE80211_RADIOTAP_EHT_DATA3_RU_ALLOC_CC_1_2_2_KNOWN |
   ATH12K_LE64_DEC_ENC(ofdma_cmn_eb2->info0,
         HAL_RX_EHT_SIG_OFDMA_EB2_RU_ALLOC_2_2,
         ru_122);
  eht->data[3] = cpu_to_le32(data);

  fallthrough;
 case HAL_EHT_BW_80:
  data = __le32_to_cpu(eht->data[2]);
  /* CC1 1::2 */
  data |= IEEE80211_RADIOTAP_EHT_DATA2_RU_ALLOC_CC_1_1_2_KNOWN |
   ATH12K_LE64_DEC_ENC(ofdma_cmn_eb1->info0,
         HAL_RX_EHT_SIG_OFDMA_EB1_RU_ALLOC_1_2,
         ru_112);
  eht->data[2] = cpu_to_le32(data);

  fallthrough;
 case HAL_EHT_BW_40:
  fallthrough;
 case HAL_EHT_BW_20:
  data = __le32_to_cpu(eht->data[1]);
  /* CC1 1::1 */
  data |= IEEE80211_RADIOTAP_EHT_DATA1_RU_ALLOC_CC_1_1_1_KNOWN |
   ATH12K_LE64_DEC_ENC(ofdma_cmn_eb1->info0,
         HAL_RX_EHT_SIG_OFDMA_EB1_RU_ALLOC_1_1,
         ru_111);
  eht->data[1] = cpu_to_le32(data);
  break;
 default:
  break;
 }
}

static void
ath12k_dp_mon_hal_rx_parse_eht_sig_ofdma(const void *tlv,
      struct hal_rx_mon_ppdu_info *ppdu_info)
{
 const struct hal_eht_sig_ofdma_cmn_eb *ofdma = tlv;

 ath12k_dp_mon_hal_rx_parse_usig_overflow(tlv, ppdu_info);
 ath12k_dp_mon_hal_rx_parse_ru_allocation(ofdma, ppdu_info);

 ath12k_dp_mon_hal_rx_parse_eht_non_mumimo_user(&ofdma->user_field.n_mu_mimo,
             ppdu_info);
}

static void
ath12k_dp_mon_parse_eht_sig_hdr(struct hal_rx_mon_ppdu_info *ppdu_info,
    const void *tlv_data)
{
 ppdu_info->is_eht = true;

 if (ath12k_dp_mon_hal_rx_is_frame_type_ndp(&ppdu_info->u_sig_info))
  ath12k_dp_mon_hal_rx_parse_eht_sig_ndp(tlv_data, ppdu_info);
 else if (ath12k_dp_mon_hal_rx_is_non_ofdma(&ppdu_info->u_sig_info))
  ath12k_dp_mon_hal_rx_parse_eht_sig_non_ofdma(tlv_data, ppdu_info);
 else if (ath12k_dp_mon_hal_rx_is_ofdma(&ppdu_info->u_sig_info))
  ath12k_dp_mon_hal_rx_parse_eht_sig_ofdma(tlv_data, ppdu_info);
}

static inline enum ath12k_eht_ru_size
hal_rx_mon_hal_ru_size_to_ath12k_ru_size(u32 hal_ru_size)
{
 switch (hal_ru_size) {
 case HAL_EHT_RU_26:
  return ATH12K_EHT_RU_26;
 case HAL_EHT_RU_52:
  return ATH12K_EHT_RU_52;
 case HAL_EHT_RU_78:
  return ATH12K_EHT_RU_52_26;
 case HAL_EHT_RU_106:
  return ATH12K_EHT_RU_106;
 case HAL_EHT_RU_132:
  return ATH12K_EHT_RU_106_26;
 case HAL_EHT_RU_242:
  return ATH12K_EHT_RU_242;
 case HAL_EHT_RU_484:
  return ATH12K_EHT_RU_484;
 case HAL_EHT_RU_726:
  return ATH12K_EHT_RU_484_242;
 case HAL_EHT_RU_996:
  return ATH12K_EHT_RU_996;
 case HAL_EHT_RU_996x2:
  return ATH12K_EHT_RU_996x2;
 case HAL_EHT_RU_996x3:
  return ATH12K_EHT_RU_996x3;
 case HAL_EHT_RU_996x4:
  return ATH12K_EHT_RU_996x4;
 case HAL_EHT_RU_NONE:
  return ATH12K_EHT_RU_INVALID;
 case HAL_EHT_RU_996_484:
  return ATH12K_EHT_RU_996_484;
 case HAL_EHT_RU_996x2_484:
  return ATH12K_EHT_RU_996x2_484;
 case HAL_EHT_RU_996x3_484:
  return ATH12K_EHT_RU_996x3_484;
 case HAL_EHT_RU_996_484_242:
  return ATH12K_EHT_RU_996_484_242;
 default:
  return ATH12K_EHT_RU_INVALID;
 }
}

static inline u32
hal_rx_ul_ofdma_ru_size_to_width(enum ath12k_eht_ru_size ru_size)
{
 switch (ru_size) {
 case ATH12K_EHT_RU_26:
  return RU_26;
 case ATH12K_EHT_RU_52:
  return RU_52;
 case ATH12K_EHT_RU_52_26:
  return RU_52_26;
 case ATH12K_EHT_RU_106:
  return RU_106;
 case ATH12K_EHT_RU_106_26:
  return RU_106_26;
 case ATH12K_EHT_RU_242:
  return RU_242;
 case ATH12K_EHT_RU_484:
  return RU_484;
 case ATH12K_EHT_RU_484_242:
  return RU_484_242;
 case ATH12K_EHT_RU_996:
  return RU_996;
 case ATH12K_EHT_RU_996_484:
  return RU_996_484;
 case ATH12K_EHT_RU_996_484_242:
  return RU_996_484_242;
 case ATH12K_EHT_RU_996x2:
  return RU_2X996;
 case ATH12K_EHT_RU_996x2_484:
  return RU_2X996_484;
 case ATH12K_EHT_RU_996x3:
  return RU_3X996;
 case ATH12K_EHT_RU_996x3_484:
  return RU_3X996_484;
 case ATH12K_EHT_RU_996x4:
  return RU_4X996;
 default:
  return RU_INVALID;
 }
}

static void
ath12k_dp_mon_hal_rx_parse_user_info(const struct hal_receive_user_info *rx_usr_info,
         u16 user_id,
         struct hal_rx_mon_ppdu_info *ppdu_info)
{
 struct hal_rx_user_status *mon_rx_user_status = NULL;
 struct hal_rx_radiotap_eht *eht = &ppdu_info->eht_info.eht;
 enum ath12k_eht_ru_size rtap_ru_size = ATH12K_EHT_RU_INVALID;
 u32 ru_width, reception_type, ru_index = HAL_EHT_RU_INVALID;
 u32 ru_type_80_0, ru_start_index_80_0;
 u32 ru_type_80_1, ru_start_index_80_1;
 u32 ru_type_80_2, ru_start_index_80_2;
 u32 ru_type_80_3, ru_start_index_80_3;
 u32 ru_size = 0, num_80mhz_with_ru = 0;
 u64 ru_index_320mhz = 0;
 u32 ru_index_per80mhz;

 reception_type = le32_get_bits(rx_usr_info->info0,
           HAL_RX_USR_INFO0_RECEPTION_TYPE);

 switch (reception_type) {
 case HAL_RECEPTION_TYPE_SU:
  ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU;
  break;
 case HAL_RECEPTION_TYPE_DL_MU_MIMO:
 case HAL_RECEPTION_TYPE_UL_MU_MIMO:
  ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_MIMO;
  break;
 case HAL_RECEPTION_TYPE_DL_MU_OFMA:
 case HAL_RECEPTION_TYPE_UL_MU_OFDMA:
  ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_OFDMA;
  break;
 case HAL_RECEPTION_TYPE_DL_MU_OFDMA_MIMO:
 case HAL_RECEPTION_TYPE_UL_MU_OFDMA_MIMO:
  ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_OFDMA_MIMO;
 }

 ppdu_info->is_stbc = le32_get_bits(rx_usr_info->info0, HAL_RX_USR_INFO0_STBC);
 ppdu_info->ldpc = le32_get_bits(rx_usr_info->info2, HAL_RX_USR_INFO2_LDPC);
 ppdu_info->dcm = le32_get_bits(rx_usr_info->info2, HAL_RX_USR_INFO2_STA_DCM);
 ppdu_info->bw = le32_get_bits(rx_usr_info->info1, HAL_RX_USR_INFO1_RX_BW);
 ppdu_info->mcs = le32_get_bits(rx_usr_info->info1, HAL_RX_USR_INFO1_MCS);
 ppdu_info->nss = le32_get_bits(rx_usr_info->info2, HAL_RX_USR_INFO2_NSS) + 1;

 if (user_id < HAL_MAX_UL_MU_USERS) {
  mon_rx_user_status = &ppdu_info->userstats[user_id];
  mon_rx_user_status->mcs = ppdu_info->mcs;
  mon_rx_user_status->nss = ppdu_info->nss;
 }

 if (!(ppdu_info->reception_type == HAL_RX_RECEPTION_TYPE_MU_MIMO ||
       ppdu_info->reception_type == HAL_RX_RECEPTION_TYPE_MU_OFDMA ||
       ppdu_info->reception_type == HAL_RX_RECEPTION_TYPE_MU_OFDMA_MIMO))
  return;

 /* RU allocation present only for OFDMA reception */
 ru_type_80_0 = le32_get_bits(rx_usr_info->info2, HAL_RX_USR_INFO2_RU_TYPE_80_0);
 ru_start_index_80_0 = le32_get_bits(rx_usr_info->info3,
         HAL_RX_USR_INFO3_RU_START_IDX_80_0);
 if (ru_type_80_0 != HAL_EHT_RU_NONE) {
  ru_size += ru_type_80_0;
  ru_index_per80mhz = ru_start_index_80_0;
  ru_index = ru_index_per80mhz;
  ru_index_320mhz |= HAL_RU_PER80(ru_type_80_0, 0, ru_index_per80mhz);
  num_80mhz_with_ru++;
 }

 ru_type_80_1 = le32_get_bits(rx_usr_info->info2, HAL_RX_USR_INFO2_RU_TYPE_80_1);
 ru_start_index_80_1 = le32_get_bits(rx_usr_info->info3,
         HAL_RX_USR_INFO3_RU_START_IDX_80_1);
 if (ru_type_80_1 != HAL_EHT_RU_NONE) {
  ru_size += ru_type_80_1;
  ru_index_per80mhz = ru_start_index_80_1;
  ru_index = ru_index_per80mhz;
  ru_index_320mhz |= HAL_RU_PER80(ru_type_80_1, 1, ru_index_per80mhz);
  num_80mhz_with_ru++;
 }

 ru_type_80_2 = le32_get_bits(rx_usr_info->info2, HAL_RX_USR_INFO2_RU_TYPE_80_2);
 ru_start_index_80_2 = le32_get_bits(rx_usr_info->info3,
         HAL_RX_USR_INFO3_RU_START_IDX_80_2);
 if (ru_type_80_2 != HAL_EHT_RU_NONE) {
  ru_size += ru_type_80_2;
  ru_index_per80mhz = ru_start_index_80_2;
  ru_index = ru_index_per80mhz;
  ru_index_320mhz |= HAL_RU_PER80(ru_type_80_2, 2, ru_index_per80mhz);
  num_80mhz_with_ru++;
 }

 ru_type_80_3 = le32_get_bits(rx_usr_info->info2, HAL_RX_USR_INFO2_RU_TYPE_80_3);
 ru_start_index_80_3 = le32_get_bits(rx_usr_info->info2,
         HAL_RX_USR_INFO3_RU_START_IDX_80_3);
 if (ru_type_80_3 != HAL_EHT_RU_NONE) {
  ru_size += ru_type_80_3;
  ru_index_per80mhz = ru_start_index_80_3;
  ru_index = ru_index_per80mhz;
  ru_index_320mhz |= HAL_RU_PER80(ru_type_80_3, 3, ru_index_per80mhz);
  num_80mhz_with_ru++;
 }

 if (num_80mhz_with_ru > 1) {
  /* Calculate the MRU index */
  switch (ru_index_320mhz) {
  case HAL_EHT_RU_996_484_0:
  case HAL_EHT_RU_996x2_484_0:
  case HAL_EHT_RU_996x3_484_0:
   ru_index = 0;
   break;
  case HAL_EHT_RU_996_484_1:
  case HAL_EHT_RU_996x2_484_1:
  case HAL_EHT_RU_996x3_484_1:
   ru_index = 1;
   break;
  case HAL_EHT_RU_996_484_2:
  case HAL_EHT_RU_996x2_484_2:
  case HAL_EHT_RU_996x3_484_2:
   ru_index = 2;
   break;
  case HAL_EHT_RU_996_484_3:
  case HAL_EHT_RU_996x2_484_3:
  case HAL_EHT_RU_996x3_484_3:
   ru_index = 3;
   break;
  case HAL_EHT_RU_996_484_4:
  case HAL_EHT_RU_996x2_484_4:
  case HAL_EHT_RU_996x3_484_4:
   ru_index = 4;
   break;
  case HAL_EHT_RU_996_484_5:
  case HAL_EHT_RU_996x2_484_5:
  case HAL_EHT_RU_996x3_484_5:
   ru_index = 5;
   break;
  case HAL_EHT_RU_996_484_6:
  case HAL_EHT_RU_996x2_484_6:
  case HAL_EHT_RU_996x3_484_6:
   ru_index = 6;
   break;
  case HAL_EHT_RU_996_484_7:
  case HAL_EHT_RU_996x2_484_7:
  case HAL_EHT_RU_996x3_484_7:
   ru_index = 7;
   break;
  case HAL_EHT_RU_996x2_484_8:
   ru_index = 8;
   break;
  case HAL_EHT_RU_996x2_484_9:
   ru_index = 9;
   break;
  case HAL_EHT_RU_996x2_484_10:
   ru_index = 10;
   break;
  case HAL_EHT_RU_996x2_484_11:
   ru_index = 11;
   break;
  default:
   ru_index = HAL_EHT_RU_INVALID;
   break;
  }

  ru_size += 4;
 }

 rtap_ru_size = hal_rx_mon_hal_ru_size_to_ath12k_ru_size(ru_size);
 if (rtap_ru_size != ATH12K_EHT_RU_INVALID) {
  u32 known, data;

  known = __le32_to_cpu(eht->known);
  known |= IEEE80211_RADIOTAP_EHT_KNOWN_RU_MRU_SIZE_OM;
  eht->known = cpu_to_le32(known);

  data = __le32_to_cpu(eht->data[1]);
  data |= u32_encode_bits(rtap_ru_size,
     IEEE80211_RADIOTAP_EHT_DATA1_RU_SIZE);
  eht->data[1] = cpu_to_le32(data);
 }

 if (ru_index != HAL_EHT_RU_INVALID) {
  u32 known, data;

  known = __le32_to_cpu(eht->known);
  known |= IEEE80211_RADIOTAP_EHT_KNOWN_RU_MRU_INDEX_OM;
  eht->known = cpu_to_le32(known);

  data = __le32_to_cpu(eht->data[1]);
  data |= u32_encode_bits(rtap_ru_size,
     IEEE80211_RADIOTAP_EHT_DATA1_RU_INDEX);
  eht->data[1] = cpu_to_le32(data);
 }

 if (mon_rx_user_status && ru_index != HAL_EHT_RU_INVALID &&
     rtap_ru_size != ATH12K_EHT_RU_INVALID) {
  mon_rx_user_status->ul_ofdma_ru_start_index = ru_index;
  mon_rx_user_status->ul_ofdma_ru_size = rtap_ru_size;

  ru_width = hal_rx_ul_ofdma_ru_size_to_width(rtap_ru_size);

  mon_rx_user_status->ul_ofdma_ru_width = ru_width;
  mon_rx_user_status->ofdma_info_valid = 1;
 }
}

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 void
ath12k_parse_cmn_usr_info(const struct hal_phyrx_common_user_info *cmn_usr_info,
     struct hal_rx_mon_ppdu_info *ppdu_info)
{
 struct hal_rx_radiotap_eht *eht = &ppdu_info->eht_info.eht;
 u32 known, data, cp_setting, ltf_size;

 known = __le32_to_cpu(eht->known);
 known |= IEEE80211_RADIOTAP_EHT_KNOWN_GI |
  IEEE80211_RADIOTAP_EHT_KNOWN_EHT_LTF;
 eht->known = cpu_to_le32(known);

 cp_setting = le32_get_bits(cmn_usr_info->info0,
       HAL_RX_CMN_USR_INFO0_CP_SETTING);
 ltf_size = le32_get_bits(cmn_usr_info->info0,
     HAL_RX_CMN_USR_INFO0_LTF_SIZE);

 data = __le32_to_cpu(eht->data[0]);
 data |= u32_encode_bits(cp_setting, IEEE80211_RADIOTAP_EHT_DATA0_GI);
 data |= u32_encode_bits(ltf_size, IEEE80211_RADIOTAP_EHT_DATA0_LTF);
 eht->data[0] = cpu_to_le32(data);

 if (!ppdu_info->ltf_size)
  ppdu_info->ltf_size = ltf_size;
 if (!ppdu_info->gi)
  ppdu_info->gi = cp_setting;
}

static void
ath12k_dp_mon_parse_status_msdu_end(struct ath12k_mon_data *pmon,
        const struct hal_rx_msdu_end *msdu_end)
{
 ath12k_dp_mon_parse_rx_msdu_end_err(__le32_to_cpu(msdu_end->info2),
         &pmon->err_bitmap);
 pmon->decap_format = le32_get_bits(msdu_end->info1,
        RX_MSDU_END_INFO11_DECAP_FORMAT);
}

static enum hal_rx_mon_status
ath12k_dp_mon_rx_parse_status_tlv(struct ath12k *ar,
      struct ath12k_mon_data *pmon,
      const struct hal_tlv_64_hdr *tlv)
{
 struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info;
 const void *tlv_data = tlv->value;
 u32 info[7], userid;
 u16 tlv_tag, tlv_len;

 tlv_tag = le64_get_bits(tlv->tl, HAL_TLV_64_HDR_TAG);
 tlv_len = le64_get_bits(tlv->tl, HAL_TLV_64_HDR_LEN);
 userid = le64_get_bits(tlv->tl, HAL_TLV_64_USR_ID);

 if (ppdu_info->tlv_aggr.in_progress && ppdu_info->tlv_aggr.tlv_tag != tlv_tag) {
  ath12k_dp_mon_parse_eht_sig_hdr(ppdu_info, ppdu_info->tlv_aggr.buf);

  ppdu_info->tlv_aggr.in_progress = false;
  ppdu_info->tlv_aggr.cur_len = 0;
 }

 switch (tlv_tag) {
 case HAL_RX_PPDU_START: {
  const struct hal_rx_ppdu_start *ppdu_start = tlv_data;

  u64 ppdu_ts = ath12k_le32hilo_to_u64(ppdu_start->ppdu_start_ts_63_32,
           ppdu_start->ppdu_start_ts_31_0);

  info[0] = __le32_to_cpu(ppdu_start->info0);

  ppdu_info->ppdu_id = u32_get_bits(info[0],
        HAL_RX_PPDU_START_INFO0_PPDU_ID);

  info[1] = __le32_to_cpu(ppdu_start->info1);
  ppdu_info->chan_num = u32_get_bits(info[1],
         HAL_RX_PPDU_START_INFO1_CHAN_NUM);
  ppdu_info->freq = u32_get_bits(info[1],
            HAL_RX_PPDU_START_INFO1_CHAN_FREQ);
  ppdu_info->ppdu_ts = ppdu_ts;

  if (ppdu_info->ppdu_id != ppdu_info->last_ppdu_id) {
   ppdu_info->last_ppdu_id = ppdu_info->ppdu_id;
   ppdu_info->num_users = 0;
   memset(&ppdu_info->mpdu_fcs_ok_bitmap, 0,
          HAL_RX_NUM_WORDS_PER_PPDU_BITMAP *
          sizeof(ppdu_info->mpdu_fcs_ok_bitmap[0]));
  }
  break;
 }
 case HAL_RX_PPDU_END_USER_STATS: {
  const struct hal_rx_ppdu_end_user_stats *eu_stats = tlv_data;
  u32 tid_bitmap;

  info[0] = __le32_to_cpu(eu_stats->info0);
  info[1] = __le32_to_cpu(eu_stats->info1);
  info[2] = __le32_to_cpu(eu_stats->info2);
  info[4] = __le32_to_cpu(eu_stats->info4);
  info[5] = __le32_to_cpu(eu_stats->info5);
  info[6] = __le32_to_cpu(eu_stats->info6);

  ppdu_info->ast_index =
   u32_get_bits(info[2], HAL_RX_PPDU_END_USER_STATS_INFO2_AST_INDEX);
  ppdu_info->fc_valid =
   u32_get_bits(info[1], HAL_RX_PPDU_END_USER_STATS_INFO1_FC_VALID);
  tid_bitmap = u32_get_bits(info[6],
       HAL_RX_PPDU_END_USER_STATS_INFO6_TID_BITMAP);
  ppdu_info->tid = ffs(tid_bitmap) - 1;
  ppdu_info->tcp_msdu_count =
   u32_get_bits(info[4],
         HAL_RX_PPDU_END_USER_STATS_INFO4_TCP_MSDU_CNT);
  ppdu_info->udp_msdu_count =
   u32_get_bits(info[4],
         HAL_RX_PPDU_END_USER_STATS_INFO4_UDP_MSDU_CNT);
  ppdu_info->other_msdu_count =
   u32_get_bits(info[5],
         HAL_RX_PPDU_END_USER_STATS_INFO5_OTHER_MSDU_CNT);
  ppdu_info->tcp_ack_msdu_count =
   u32_get_bits(info[5],
         HAL_RX_PPDU_END_USER_STATS_INFO5_TCP_ACK_MSDU_CNT);
  ppdu_info->preamble_type =
   u32_get_bits(info[1],
         HAL_RX_PPDU_END_USER_STATS_INFO1_PKT_TYPE);
  ppdu_info->num_mpdu_fcs_ok =
   u32_get_bits(info[1],
         HAL_RX_PPDU_END_USER_STATS_INFO1_MPDU_CNT_FCS_OK);
  ppdu_info->num_mpdu_fcs_err =
   u32_get_bits(info[0],
         HAL_RX_PPDU_END_USER_STATS_INFO0_MPDU_CNT_FCS_ERR);
  ppdu_info->peer_id =
   u32_get_bits(info[0], HAL_RX_PPDU_END_USER_STATS_INFO0_PEER_ID);

  switch (ppdu_info->preamble_type) {
  case HAL_RX_PREAMBLE_11N:
   ppdu_info->ht_flags = 1;
   break;
  case HAL_RX_PREAMBLE_11AC:
   ppdu_info->vht_flags = 1;
   break;
  case HAL_RX_PREAMBLE_11AX:
   ppdu_info->he_flags = 1;
   break;
  case HAL_RX_PREAMBLE_11BE:
   ppdu_info->is_eht = true;
   break;
  default:
   break;
  }

  if (userid < HAL_MAX_UL_MU_USERS) {
   struct hal_rx_user_status *rxuser_stats =
    &ppdu_info->userstats[userid];

   if (ppdu_info->num_mpdu_fcs_ok > 1 ||
       ppdu_info->num_mpdu_fcs_err > 1)
    ppdu_info->userstats[userid].ampdu_present = true;

   ppdu_info->num_users += 1;

   ath12k_dp_mon_rx_handle_ofdma_info(eu_stats, rxuser_stats);
   ath12k_dp_mon_rx_populate_mu_user_info(eu_stats, ppdu_info,
              rxuser_stats);
  }
  ppdu_info->mpdu_fcs_ok_bitmap[0] = __le32_to_cpu(eu_stats->rsvd1[0]);
  ppdu_info->mpdu_fcs_ok_bitmap[1] = __le32_to_cpu(eu_stats->rsvd1[1]);
  break;
 }
 case HAL_RX_PPDU_END_USER_STATS_EXT: {
  const struct hal_rx_ppdu_end_user_stats_ext *eu_stats = tlv_data;

  ppdu_info->mpdu_fcs_ok_bitmap[2] = __le32_to_cpu(eu_stats->info1);
  ppdu_info->mpdu_fcs_ok_bitmap[3] = __le32_to_cpu(eu_stats->info2);
  ppdu_info->mpdu_fcs_ok_bitmap[4] = __le32_to_cpu(eu_stats->info3);
  ppdu_info->mpdu_fcs_ok_bitmap[5] = __le32_to_cpu(eu_stats->info4);
  ppdu_info->mpdu_fcs_ok_bitmap[6] = __le32_to_cpu(eu_stats->info5);
  ppdu_info->mpdu_fcs_ok_bitmap[7] = __le32_to_cpu(eu_stats->info6);
  break;
 }
 case HAL_PHYRX_HT_SIG:
  ath12k_dp_mon_parse_ht_sig(tlv_data, ppdu_info);
  break;

 case HAL_PHYRX_L_SIG_B:
  ath12k_dp_mon_parse_l_sig_b(tlv_data, ppdu_info);
  break;

 case HAL_PHYRX_L_SIG_A:
  ath12k_dp_mon_parse_l_sig_a(tlv_data, ppdu_info);
  break;

 case HAL_PHYRX_VHT_SIG_A:
  ath12k_dp_mon_parse_vht_sig_a(tlv_data, ppdu_info);
  break;

 case HAL_PHYRX_HE_SIG_A_SU:
  ath12k_dp_mon_parse_he_sig_su(tlv_data, ppdu_info);
  break;

 case HAL_PHYRX_HE_SIG_A_MU_DL:
  ath12k_dp_mon_parse_he_sig_mu(tlv_data, ppdu_info);
  break;

 case HAL_PHYRX_HE_SIG_B1_MU:
  ath12k_dp_mon_parse_he_sig_b1_mu(tlv_data, ppdu_info);
  break;

 case HAL_PHYRX_HE_SIG_B2_MU:
  ath12k_dp_mon_parse_he_sig_b2_mu(tlv_data, ppdu_info);
  break;

 case HAL_PHYRX_HE_SIG_B2_OFDMA:
  ath12k_dp_mon_parse_he_sig_b2_ofdma(tlv_data, ppdu_info);
  break;

 case HAL_PHYRX_RSSI_LEGACY: {
  const struct hal_rx_phyrx_rssi_legacy_info *rssi = tlv_data;

  info[0] = __le32_to_cpu(rssi->info0);
  info[2] = __le32_to_cpu(rssi->info2);

  /* TODO: Please note that the combined rssi will not be accurate
 * in MU case. Rssi in MU needs to be retrieved from
 * PHYRX_OTHER_RECEIVE_INFO TLV.
 */

  ppdu_info->rssi_comb =
   u32_get_bits(info[2],
         HAL_RX_RSSI_LEGACY_INFO_INFO2_RSSI_COMB_PPDU);

  ppdu_info->bw = u32_get_bits(info[0],
          HAL_RX_RSSI_LEGACY_INFO_INFO0_RX_BW);
  break;
 }
 case HAL_PHYRX_COMMON_USER_INFO: {
  ath12k_parse_cmn_usr_info(tlv_data, ppdu_info);
  break;
 }
 case HAL_RX_PPDU_START_USER_INFO:
  ath12k_dp_mon_hal_rx_parse_user_info(tlv_data, userid, ppdu_info);
  break;

 case HAL_RXPCU_PPDU_END_INFO: {
  const struct hal_rx_ppdu_end_duration *ppdu_rx_duration = tlv_data;

  info[0] = __le32_to_cpu(ppdu_rx_duration->info0);
  ppdu_info->rx_duration =
   u32_get_bits(info[0], HAL_RX_PPDU_END_DURATION);
  ppdu_info->tsft = __le32_to_cpu(ppdu_rx_duration->rsvd0[1]);
  ppdu_info->tsft = (ppdu_info->tsft << 32) |
       __le32_to_cpu(ppdu_rx_duration->rsvd0[0]);
  break;
 }
 case HAL_RX_MPDU_START: {
  const struct hal_rx_mpdu_start *mpdu_start = tlv_data;
  u16 peer_id;

  info[1] = __le32_to_cpu(mpdu_start->info1);
  peer_id = u32_get_bits(info[1], HAL_RX_MPDU_START_INFO1_PEERID);
  if (peer_id)
   ppdu_info->peer_id = peer_id;

  ppdu_info->mpdu_len += u32_get_bits(info[1],
          HAL_RX_MPDU_START_INFO2_MPDU_LEN);
  if (userid < HAL_MAX_UL_MU_USERS) {
   info[0] = __le32_to_cpu(mpdu_start->info0);
   ppdu_info->userid = userid;
   ppdu_info->userstats[userid].ampdu_id =
    u32_get_bits(info[0], HAL_RX_MPDU_START_INFO0_PPDU_ID);
  }

  return HAL_RX_MON_STATUS_MPDU_START;
 }
 case HAL_RX_MSDU_START:
  /* TODO: add msdu start parsing logic */
  break;
 case HAL_MON_BUF_ADDR:
  return HAL_RX_MON_STATUS_BUF_ADDR;
 case HAL_RX_MSDU_END:
  ath12k_dp_mon_parse_status_msdu_end(pmon, tlv_data);
  return HAL_RX_MON_STATUS_MSDU_END;
 case HAL_RX_MPDU_END:
  return HAL_RX_MON_STATUS_MPDU_END;
 case HAL_PHYRX_GENERIC_U_SIG:
  ath12k_dp_mon_hal_rx_parse_u_sig_hdr(tlv_data, ppdu_info);
  break;
 case HAL_PHYRX_GENERIC_EHT_SIG:
  /* Handle the case where aggregation is in progress
 * or the current TLV is one of the TLVs which should be
 * aggregated
 */

  if (!ppdu_info->tlv_aggr.in_progress) {
   ppdu_info->tlv_aggr.in_progress = true;
   ppdu_info->tlv_aggr.tlv_tag = tlv_tag;
   ppdu_info->tlv_aggr.cur_len = 0;
  }

  ppdu_info->is_eht = true;

  ath12k_dp_mon_hal_aggr_tlv(ppdu_info, tlv_len, tlv_data);
  break;
 case HAL_DUMMY:
  return HAL_RX_MON_STATUS_BUF_DONE;
 case HAL_RX_PPDU_END_STATUS_DONE:
 case 0:
  return HAL_RX_MON_STATUS_PPDU_DONE;
 default:
  break;
 }

 return HAL_RX_MON_STATUS_PPDU_NOT_DONE;
}

static void
ath12k_dp_mon_fill_rx_stats_info(struct ath12k *ar,
     struct hal_rx_mon_ppdu_info *ppdu_info,
     struct ieee80211_rx_status *rx_status)
{
 u32 center_freq = ppdu_info->freq;

 rx_status->freq = center_freq;
 rx_status->bw = ath12k_mac_bw_to_mac80211_bw(ppdu_info->bw);
 rx_status->nss = ppdu_info->nss;
 rx_status->rate_idx = 0;
 rx_status->encoding = RX_ENC_LEGACY;
 rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;

 if (center_freq >= ATH12K_MIN_6GHZ_FREQ &&
     center_freq <= ATH12K_MAX_6GHZ_FREQ) {
  rx_status->band = NL80211_BAND_6GHZ;
 } else if (center_freq >= ATH12K_MIN_2GHZ_FREQ &&
     center_freq <= ATH12K_MAX_2GHZ_FREQ) {
  rx_status->band = NL80211_BAND_2GHZ;
 } else if (center_freq >= ATH12K_MIN_5GHZ_FREQ &&
     center_freq <= ATH12K_MAX_5GHZ_FREQ) {
  rx_status->band = NL80211_BAND_5GHZ;
 } else {
  rx_status->band = NUM_NL80211_BANDS;
 }
}

static struct sk_buff
*ath12k_dp_rx_alloc_mon_status_buf(struct ath12k_base *ab,
       struct dp_rxdma_mon_ring *rx_ring,
       int *buf_id)
{
 struct sk_buff *skb;
 dma_addr_t paddr;

 skb = dev_alloc_skb(RX_MON_STATUS_BUF_SIZE);

 if (!skb)
  goto fail_alloc_skb;

 if (!IS_ALIGNED((unsigned long)skb->data,
   RX_MON_STATUS_BUF_ALIGN)) {
  skb_pull(skb, PTR_ALIGN(skb->data, RX_MON_STATUS_BUF_ALIGN) -
    skb->data);
 }

 paddr = dma_map_single(ab->dev, skb->data,
          skb->len + skb_tailroom(skb),
          DMA_FROM_DEVICE);
 if (unlikely(dma_mapping_error(ab->dev, paddr)))
  goto fail_free_skb;

 spin_lock_bh(&rx_ring->idr_lock);
 *buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 0,
       rx_ring->bufs_max, GFP_ATOMIC);
 spin_unlock_bh(&rx_ring->idr_lock);
 if (*buf_id < 0)
  goto fail_dma_unmap;

 ATH12K_SKB_RXCB(skb)->paddr = paddr;
 return skb;

fail_dma_unmap:
 dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb),
    DMA_FROM_DEVICE);
fail_free_skb:
 dev_kfree_skb_any(skb);
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(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 u32 ath12k_dp_mon_comp_ppduid(u32 msdu_ppdu_id, u32 *ppdu_id)
{
 u32 ret = 0;

 if ((*ppdu_id < msdu_ppdu_id) &&
     ((msdu_ppdu_id - *ppdu_id) < DP_NOT_PPDU_ID_WRAP_AROUND)) {
  /* Hold on mon dest ring, and reap mon status ring. */
  *ppdu_id = msdu_ppdu_id;
  ret = msdu_ppdu_id;
 } else if ((*ppdu_id > msdu_ppdu_id) &&
  ((*ppdu_id - msdu_ppdu_id) > DP_NOT_PPDU_ID_WRAP_AROUND)) {
  /* PPDU ID has exceeded the maximum value and will
 * restart from 0.
 */

  *ppdu_id = msdu_ppdu_id;
  ret = msdu_ppdu_id;
 }
 return ret;
}

static
void ath12k_dp_mon_next_link_desc_get(struct hal_rx_msdu_link *msdu_link,
          dma_addr_t *paddr, u32 *sw_cookie, u8 *rbm,
          struct ath12k_buffer_addr **pp_buf_addr_info)
{
 struct ath12k_buffer_addr *buf_addr_info;

 buf_addr_info = &msdu_link->buf_addr_info;

 ath12k_hal_rx_buf_addr_info_get(buf_addr_info, paddr, sw_cookie, rbm);

 *pp_buf_addr_info = buf_addr_info;
}

static void
ath12k_dp_mon_fill_rx_rate(struct ath12k *ar,
      struct hal_rx_mon_ppdu_info *ppdu_info,
      struct ieee80211_rx_status *rx_status)
{
 struct ieee80211_supported_band *sband;
 enum rx_msdu_start_pkt_type pkt_type;
 u8 rate_mcs, nss, sgi;
 bool is_cck;

 pkt_type = ppdu_info->preamble_type;
 rate_mcs = ppdu_info->rate;
 nss = ppdu_info->nss;
 sgi = ppdu_info->gi;

 switch (pkt_type) {
 case RX_MSDU_START_PKT_TYPE_11A:
 case RX_MSDU_START_PKT_TYPE_11B:
  is_cck = (pkt_type == RX_MSDU_START_PKT_TYPE_11B);
  if (rx_status->band < NUM_NL80211_BANDS) {
   sband = &ar->mac.sbands[rx_status->band];
   rx_status->rate_idx = ath12k_mac_hw_rate_to_idx(sband, rate_mcs,
         is_cck);
  }
  break;
 case RX_MSDU_START_PKT_TYPE_11N:
  rx_status->encoding = RX_ENC_HT;
  if (rate_mcs > ATH12K_HT_MCS_MAX) {
   ath12k_warn(ar->ab,
        "Received with invalid mcs in HT mode %d\n",
         rate_mcs);
   break;
  }
  rx_status->rate_idx = rate_mcs + (8 * (nss - 1));
  if (sgi)
   rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
  break;
 case RX_MSDU_START_PKT_TYPE_11AC:
  rx_status->encoding = RX_ENC_VHT;
  rx_status->rate_idx = rate_mcs;
  if (rate_mcs > ATH12K_VHT_MCS_MAX) {
   ath12k_warn(ar->ab,
        "Received with invalid mcs in VHT mode %d\n",
         rate_mcs);
   break;
  }
  if (sgi)
   rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
  break;
 case RX_MSDU_START_PKT_TYPE_11AX:
  rx_status->rate_idx = rate_mcs;
  if (rate_mcs > ATH12K_HE_MCS_MAX) {
   ath12k_warn(ar->ab,
        "Received with invalid mcs in HE mode %d\n",
        rate_mcs);
   break;
  }
  rx_status->encoding = RX_ENC_HE;
  rx_status->he_gi = ath12k_he_gi_to_nl80211_he_gi(sgi);
  break;
 case RX_MSDU_START_PKT_TYPE_11BE:
  rx_status->rate_idx = rate_mcs;
  if (rate_mcs > ATH12K_EHT_MCS_MAX) {
   ath12k_warn(ar->ab,
        "Received with invalid mcs in EHT mode %d\n",
        rate_mcs);
   break;
  }
  rx_status->encoding = RX_ENC_EHT;
  rx_status->he_gi = ath12k_he_gi_to_nl80211_he_gi(sgi);
  break;
 default:
  ath12k_dbg(ar->ab, ATH12K_DBG_DATA,
      "monitor receives invalid preamble type %d",
       pkt_type);
  break;
 }
}

static void ath12k_dp_mon_rx_msdus_set_payload(struct ath12k *ar,
            struct sk_buff *head_msdu,
            struct sk_buff *tail_msdu)
{
 u32 rx_pkt_offset, l2_hdr_offset, total_offset;

 rx_pkt_offset = ar->ab->hal.hal_desc_sz;
 l2_hdr_offset =
  ath12k_dp_rx_h_l3pad(ar->ab, (struct hal_rx_desc *)tail_msdu->data);

 if (ar->ab->hw_params->rxdma1_enable)
  total_offset = ATH12K_MON_RX_PKT_OFFSET;
 else
  total_offset = rx_pkt_offset + l2_hdr_offset;

 skb_pull(head_msdu, total_offset);
}

static struct sk_buff *
ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar,
       struct dp_mon_mpdu *mon_mpdu,
       struct hal_rx_mon_ppdu_info *ppdu_info,
       struct ieee80211_rx_status *rxs)
{
 struct ath12k_base *ab = ar->ab;
 struct sk_buff *msdu, *mpdu_buf, *prev_buf, *head_frag_list;
 struct sk_buff *head_msdu, *tail_msdu;
 struct hal_rx_desc *rx_desc;
 u8 *hdr_desc, *dest, decap_format = mon_mpdu->decap_format;
 struct ieee80211_hdr_3addr *wh;
 struct ieee80211_channel *channel;
 u32 frag_list_sum_len = 0;
 u8 channel_num = ppdu_info->chan_num;

 mpdu_buf = NULL;
 head_msdu = mon_mpdu->head;
 tail_msdu = mon_mpdu->tail;

 if (!head_msdu || !tail_msdu)
  goto err_merge_fail;

 ath12k_dp_mon_fill_rx_stats_info(ar, ppdu_info, rxs);

 if (unlikely(rxs->band == NUM_NL80211_BANDS ||
       !ath12k_ar_to_hw(ar)->wiphy->bands[rxs->band])) {
  ath12k_dbg(ar->ab, ATH12K_DBG_DATA,
      "sband is NULL for status band %d channel_num %d center_freq %d pdev_id %d\n",
      rxs->band, channel_num, ppdu_info->freq, ar->pdev_idx);

  spin_lock_bh(&ar->data_lock);
  channel = ar->rx_channel;
  if (channel) {
   rxs->band = channel->band;
   channel_num =
    ieee80211_frequency_to_channel(channel->center_freq);
  }
  spin_unlock_bh(&ar->data_lock);
 }

 if (rxs->band < NUM_NL80211_BANDS)
  rxs->freq = ieee80211_channel_to_frequency(channel_num,
          rxs->band);

 ath12k_dp_mon_fill_rx_rate(ar, ppdu_info, rxs);

 if (decap_format == DP_RX_DECAP_TYPE_RAW) {
  ath12k_dp_mon_rx_msdus_set_payload(ar, head_msdu, tail_msdu);

  prev_buf = head_msdu;
  msdu = head_msdu->next;
  head_frag_list = NULL;

  while (msdu) {
   ath12k_dp_mon_rx_msdus_set_payload(ar, head_msdu, tail_msdu);

   if (!head_frag_list)
    head_frag_list = msdu;

   frag_list_sum_len += msdu->len;
   prev_buf = msdu;
   msdu = msdu->next;
  }

  prev_buf->next = NULL;

  skb_trim(prev_buf, prev_buf->len);
  if (head_frag_list) {
   skb_shinfo(head_msdu)->frag_list = head_frag_list;
   head_msdu->data_len = frag_list_sum_len;
   head_msdu->len += head_msdu->data_len;
   head_msdu->next = NULL;
  }
 } else if (decap_format == DP_RX_DECAP_TYPE_NATIVE_WIFI) {
  u8 qos_pkt = 0;

  rx_desc = (struct hal_rx_desc *)head_msdu->data;
  hdr_desc =
   ab->hal_rx_ops->rx_desc_get_msdu_payload(rx_desc);

  /* Base size */
  wh = (struct ieee80211_hdr_3addr *)hdr_desc;

  if (ieee80211_is_data_qos(wh->frame_control))
   qos_pkt = 1;

  msdu = head_msdu;

  while (msdu) {
   ath12k_dp_mon_rx_msdus_set_payload(ar, head_msdu, tail_msdu);
   if (qos_pkt) {
    dest = skb_push(msdu, sizeof(__le16));
    if (!dest)
     goto err_merge_fail;
    memcpy(dest, hdr_desc, sizeof(struct ieee80211_qos_hdr));
   }
   prev_buf = msdu;
   msdu = msdu->next;
  }
  dest = skb_put(prev_buf, HAL_RX_FCS_LEN);
  if (!dest)
   goto err_merge_fail;

  ath12k_dbg(ab, ATH12K_DBG_DATA,
      "mpdu_buf %p mpdu_buf->len %u",
      prev_buf, prev_buf->len);
 } else {
  ath12k_dbg(ab, ATH12K_DBG_DATA,
      "decap format %d is not supported!\n",
      decap_format);
  goto err_merge_fail;
 }

 return head_msdu;

err_merge_fail:
 if (mpdu_buf && decap_format != DP_RX_DECAP_TYPE_RAW) {
  ath12k_dbg(ab, ATH12K_DBG_DATA,
      "err_merge_fail mpdu_buf %p", mpdu_buf);
  /* Free the head buffer */
  dev_kfree_skb_any(mpdu_buf);
 }
 return NULL;
}

static void
ath12k_dp_mon_rx_update_radiotap_he(struct hal_rx_mon_ppdu_info *rx_status,
        u8 *rtap_buf)
{
 u32 rtap_len = 0;

 put_unaligned_le16(rx_status->he_data1, &rtap_buf[rtap_len]);
 rtap_len += 2;

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=97 H=95 G=95

¤ Dauer der Verarbeitung: 0.25 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge