1d5c65159SKalle Valo // SPDX-License-Identifier: BSD-3-Clause-Clear 2d5c65159SKalle Valo /* 3d5c65159SKalle Valo * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. 4d5c65159SKalle Valo */ 5d5c65159SKalle Valo 6d5c65159SKalle Valo #include <linux/ieee80211.h> 7acc79d98SSriram R #include <linux/kernel.h> 8acc79d98SSriram R #include <linux/skbuff.h> 9243874c6SManikanta Pubbisetty #include <crypto/hash.h> 10d5c65159SKalle Valo #include "core.h" 11d5c65159SKalle Valo #include "debug.h" 12568f0603SKalle Valo #include "debugfs_htt_stats.h" 13568f0603SKalle Valo #include "debugfs_sta.h" 14d5c65159SKalle Valo #include "hal_desc.h" 15d5c65159SKalle Valo #include "hw.h" 16d5c65159SKalle Valo #include "dp_rx.h" 17d5c65159SKalle Valo #include "hal_rx.h" 18d5c65159SKalle Valo #include "dp_tx.h" 19d5c65159SKalle Valo #include "peer.h" 20d5c65159SKalle Valo 21243874c6SManikanta Pubbisetty #define ATH11K_DP_RX_FRAGMENT_TIMEOUT_MS (2 * HZ) 22243874c6SManikanta Pubbisetty 235e76fe03SP Praneesh static inline 245e76fe03SP Praneesh u8 *ath11k_dp_rx_h_80211_hdr(struct ath11k_base *ab, struct hal_rx_desc *desc) 25d5c65159SKalle Valo { 26e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_hdr_status(desc); 27d5c65159SKalle Valo } 28d5c65159SKalle Valo 295e76fe03SP Praneesh static inline 305e76fe03SP Praneesh enum hal_encrypt_type ath11k_dp_rx_h_mpdu_start_enctype(struct ath11k_base *ab, 31e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 32d5c65159SKalle Valo { 33e678fbd4SKarthikeyan Periyasamy if (!ab->hw_params.hw_ops->rx_desc_encrypt_valid(desc)) 34d5c65159SKalle Valo return HAL_ENCRYPT_TYPE_OPEN; 35d5c65159SKalle Valo 36e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_encrypt_type(desc); 37d5c65159SKalle Valo } 38d5c65159SKalle Valo 395e76fe03SP Praneesh static inline u8 ath11k_dp_rx_h_msdu_start_decap_type(struct ath11k_base *ab, 40e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 41d5c65159SKalle Valo { 42e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_decap_type(desc); 43243874c6SManikanta Pubbisetty } 44243874c6SManikanta Pubbisetty 455e76fe03SP Praneesh static inline 46b3febdccSP Praneesh bool ath11k_dp_rx_h_msdu_start_ldpc_support(struct ath11k_base *ab, 47b3febdccSP Praneesh struct hal_rx_desc *desc) 48b3febdccSP Praneesh { 49b3febdccSP Praneesh return ab->hw_params.hw_ops->rx_desc_get_ldpc_support(desc); 50b3febdccSP Praneesh } 51b3febdccSP Praneesh 52b3febdccSP Praneesh static inline 535e76fe03SP Praneesh u8 ath11k_dp_rx_h_msdu_start_mesh_ctl_present(struct ath11k_base *ab, 54e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 55acc79d98SSriram R { 56e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_mesh_ctl(desc); 57acc79d98SSriram R } 58acc79d98SSriram R 595e76fe03SP Praneesh static inline 605e76fe03SP Praneesh bool ath11k_dp_rx_h_mpdu_start_seq_ctrl_valid(struct ath11k_base *ab, 61e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 62243874c6SManikanta Pubbisetty { 63e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_mpdu_seq_ctl_vld(desc); 64243874c6SManikanta Pubbisetty } 65243874c6SManikanta Pubbisetty 665e76fe03SP Praneesh static inline bool ath11k_dp_rx_h_mpdu_start_fc_valid(struct ath11k_base *ab, 67e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 68243874c6SManikanta Pubbisetty { 69e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_mpdu_fc_valid(desc); 70243874c6SManikanta Pubbisetty } 71243874c6SManikanta Pubbisetty 725e76fe03SP Praneesh static inline bool ath11k_dp_rx_h_mpdu_start_more_frags(struct ath11k_base *ab, 73e678fbd4SKarthikeyan Periyasamy struct sk_buff *skb) 74243874c6SManikanta Pubbisetty { 75243874c6SManikanta Pubbisetty struct ieee80211_hdr *hdr; 76243874c6SManikanta Pubbisetty 77e678fbd4SKarthikeyan Periyasamy hdr = (struct ieee80211_hdr *)(skb->data + ab->hw_params.hal_desc_sz); 78243874c6SManikanta Pubbisetty return ieee80211_has_morefrags(hdr->frame_control); 79243874c6SManikanta Pubbisetty } 80243874c6SManikanta Pubbisetty 815e76fe03SP Praneesh static inline u16 ath11k_dp_rx_h_mpdu_start_frag_no(struct ath11k_base *ab, 82e678fbd4SKarthikeyan Periyasamy struct sk_buff *skb) 83243874c6SManikanta Pubbisetty { 84243874c6SManikanta Pubbisetty struct ieee80211_hdr *hdr; 85243874c6SManikanta Pubbisetty 86e678fbd4SKarthikeyan Periyasamy hdr = (struct ieee80211_hdr *)(skb->data + ab->hw_params.hal_desc_sz); 87243874c6SManikanta Pubbisetty return le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; 88243874c6SManikanta Pubbisetty } 89243874c6SManikanta Pubbisetty 905e76fe03SP Praneesh static inline u16 ath11k_dp_rx_h_mpdu_start_seq_no(struct ath11k_base *ab, 91e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 92243874c6SManikanta Pubbisetty { 93e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_mpdu_start_seq_no(desc); 94d5c65159SKalle Valo } 95d5c65159SKalle Valo 965e76fe03SP Praneesh static inline void *ath11k_dp_rx_get_attention(struct ath11k_base *ab, 97e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 98e678fbd4SKarthikeyan Periyasamy { 99e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_attention(desc); 100e678fbd4SKarthikeyan Periyasamy } 101e678fbd4SKarthikeyan Periyasamy 1025e76fe03SP Praneesh static inline bool ath11k_dp_rx_h_attn_msdu_done(struct rx_attention *attn) 103d5c65159SKalle Valo { 104d5c65159SKalle Valo return !!FIELD_GET(RX_ATTENTION_INFO2_MSDU_DONE, 105e678fbd4SKarthikeyan Periyasamy __le32_to_cpu(attn->info2)); 106d5c65159SKalle Valo } 107d5c65159SKalle Valo 1085e76fe03SP Praneesh static inline bool ath11k_dp_rx_h_attn_l4_cksum_fail(struct rx_attention *attn) 109d5c65159SKalle Valo { 110d5c65159SKalle Valo return !!FIELD_GET(RX_ATTENTION_INFO1_TCP_UDP_CKSUM_FAIL, 111e678fbd4SKarthikeyan Periyasamy __le32_to_cpu(attn->info1)); 112d5c65159SKalle Valo } 113d5c65159SKalle Valo 1145e76fe03SP Praneesh static inline bool ath11k_dp_rx_h_attn_ip_cksum_fail(struct rx_attention *attn) 115d5c65159SKalle Valo { 116d5c65159SKalle Valo return !!FIELD_GET(RX_ATTENTION_INFO1_IP_CKSUM_FAIL, 117e678fbd4SKarthikeyan Periyasamy __le32_to_cpu(attn->info1)); 118d5c65159SKalle Valo } 119d5c65159SKalle Valo 1205e76fe03SP Praneesh static inline bool ath11k_dp_rx_h_attn_is_decrypted(struct rx_attention *attn) 121d5c65159SKalle Valo { 122d5c65159SKalle Valo return (FIELD_GET(RX_ATTENTION_INFO2_DCRYPT_STATUS_CODE, 123e678fbd4SKarthikeyan Periyasamy __le32_to_cpu(attn->info2)) == 124d5c65159SKalle Valo RX_DESC_DECRYPT_STATUS_CODE_OK); 125d5c65159SKalle Valo } 126d5c65159SKalle Valo 127e678fbd4SKarthikeyan Periyasamy static u32 ath11k_dp_rx_h_attn_mpdu_err(struct rx_attention *attn) 128d5c65159SKalle Valo { 129e678fbd4SKarthikeyan Periyasamy u32 info = __le32_to_cpu(attn->info1); 130d5c65159SKalle Valo u32 errmap = 0; 131d5c65159SKalle Valo 132d5c65159SKalle Valo if (info & RX_ATTENTION_INFO1_FCS_ERR) 133d5c65159SKalle Valo errmap |= DP_RX_MPDU_ERR_FCS; 134d5c65159SKalle Valo 135d5c65159SKalle Valo if (info & RX_ATTENTION_INFO1_DECRYPT_ERR) 136d5c65159SKalle Valo errmap |= DP_RX_MPDU_ERR_DECRYPT; 137d5c65159SKalle Valo 138d5c65159SKalle Valo if (info & RX_ATTENTION_INFO1_TKIP_MIC_ERR) 139d5c65159SKalle Valo errmap |= DP_RX_MPDU_ERR_TKIP_MIC; 140d5c65159SKalle Valo 141d5c65159SKalle Valo if (info & RX_ATTENTION_INFO1_A_MSDU_ERROR) 142d5c65159SKalle Valo errmap |= DP_RX_MPDU_ERR_AMSDU_ERR; 143d5c65159SKalle Valo 144d5c65159SKalle Valo if (info & RX_ATTENTION_INFO1_OVERFLOW_ERR) 145d5c65159SKalle Valo errmap |= DP_RX_MPDU_ERR_OVERFLOW; 146d5c65159SKalle Valo 147d5c65159SKalle Valo if (info & RX_ATTENTION_INFO1_MSDU_LEN_ERR) 148d5c65159SKalle Valo errmap |= DP_RX_MPDU_ERR_MSDU_LEN; 149d5c65159SKalle Valo 150d5c65159SKalle Valo if (info & RX_ATTENTION_INFO1_MPDU_LEN_ERR) 151d5c65159SKalle Valo errmap |= DP_RX_MPDU_ERR_MPDU_LEN; 152d5c65159SKalle Valo 153d5c65159SKalle Valo return errmap; 154d5c65159SKalle Valo } 155d5c65159SKalle Valo 156cd18ed4cSBaochen Qiang static bool ath11k_dp_rx_h_attn_msdu_len_err(struct ath11k_base *ab, 157cd18ed4cSBaochen Qiang struct hal_rx_desc *desc) 158cd18ed4cSBaochen Qiang { 159cd18ed4cSBaochen Qiang struct rx_attention *rx_attention; 160cd18ed4cSBaochen Qiang u32 errmap; 161cd18ed4cSBaochen Qiang 162cd18ed4cSBaochen Qiang rx_attention = ath11k_dp_rx_get_attention(ab, desc); 163cd18ed4cSBaochen Qiang errmap = ath11k_dp_rx_h_attn_mpdu_err(rx_attention); 164cd18ed4cSBaochen Qiang 165cd18ed4cSBaochen Qiang return errmap & DP_RX_MPDU_ERR_MSDU_LEN; 166cd18ed4cSBaochen Qiang } 167cd18ed4cSBaochen Qiang 1685e76fe03SP Praneesh static inline u16 ath11k_dp_rx_h_msdu_start_msdu_len(struct ath11k_base *ab, 169e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 170d5c65159SKalle Valo { 171e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_msdu_len(desc); 172d5c65159SKalle Valo } 173d5c65159SKalle Valo 1745e76fe03SP Praneesh static inline u8 ath11k_dp_rx_h_msdu_start_sgi(struct ath11k_base *ab, 175e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 176d5c65159SKalle Valo { 177e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_msdu_sgi(desc); 178d5c65159SKalle Valo } 179d5c65159SKalle Valo 1805e76fe03SP Praneesh static inline u8 ath11k_dp_rx_h_msdu_start_rate_mcs(struct ath11k_base *ab, 181e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 182d5c65159SKalle Valo { 183e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_msdu_rate_mcs(desc); 184d5c65159SKalle Valo } 185d5c65159SKalle Valo 1865e76fe03SP Praneesh static inline u8 ath11k_dp_rx_h_msdu_start_rx_bw(struct ath11k_base *ab, 187e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 188d5c65159SKalle Valo { 189e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_msdu_rx_bw(desc); 190d5c65159SKalle Valo } 191d5c65159SKalle Valo 1925e76fe03SP Praneesh static inline u32 ath11k_dp_rx_h_msdu_start_freq(struct ath11k_base *ab, 193e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 194d5c65159SKalle Valo { 195e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_msdu_freq(desc); 196d5c65159SKalle Valo } 197d5c65159SKalle Valo 1985e76fe03SP Praneesh static inline u8 ath11k_dp_rx_h_msdu_start_pkt_type(struct ath11k_base *ab, 199e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 200d5c65159SKalle Valo { 201e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_msdu_pkt_type(desc); 202d5c65159SKalle Valo } 203d5c65159SKalle Valo 2045e76fe03SP Praneesh static inline u8 ath11k_dp_rx_h_msdu_start_nss(struct ath11k_base *ab, 205e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 206d5c65159SKalle Valo { 207e678fbd4SKarthikeyan Periyasamy return hweight8(ab->hw_params.hw_ops->rx_desc_get_msdu_nss(desc)); 208d5c65159SKalle Valo } 209d5c65159SKalle Valo 2105e76fe03SP Praneesh static inline u8 ath11k_dp_rx_h_mpdu_start_tid(struct ath11k_base *ab, 211e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 212243874c6SManikanta Pubbisetty { 213e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_mpdu_tid(desc); 214243874c6SManikanta Pubbisetty } 215243874c6SManikanta Pubbisetty 2165e76fe03SP Praneesh static inline u16 ath11k_dp_rx_h_mpdu_start_peer_id(struct ath11k_base *ab, 217e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 218243874c6SManikanta Pubbisetty { 219e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_mpdu_peer_id(desc); 220243874c6SManikanta Pubbisetty } 221243874c6SManikanta Pubbisetty 2225e76fe03SP Praneesh static inline u8 ath11k_dp_rx_h_msdu_end_l3pad(struct ath11k_base *ab, 223e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 224d5c65159SKalle Valo { 225e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_l3_pad_bytes(desc); 226d5c65159SKalle Valo } 227d5c65159SKalle Valo 2285e76fe03SP Praneesh static inline bool ath11k_dp_rx_h_msdu_end_first_msdu(struct ath11k_base *ab, 229e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 230d5c65159SKalle Valo { 231e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_first_msdu(desc); 232d5c65159SKalle Valo } 233d5c65159SKalle Valo 234e678fbd4SKarthikeyan Periyasamy static bool ath11k_dp_rx_h_msdu_end_last_msdu(struct ath11k_base *ab, 235e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc) 236d5c65159SKalle Valo { 237e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_last_msdu(desc); 238d5c65159SKalle Valo } 239d5c65159SKalle Valo 240e678fbd4SKarthikeyan Periyasamy static void ath11k_dp_rx_desc_end_tlv_copy(struct ath11k_base *ab, 241e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *fdesc, 242d5c65159SKalle Valo struct hal_rx_desc *ldesc) 243d5c65159SKalle Valo { 244e678fbd4SKarthikeyan Periyasamy ab->hw_params.hw_ops->rx_desc_copy_attn_end_tlv(fdesc, ldesc); 245d5c65159SKalle Valo } 246d5c65159SKalle Valo 2475e76fe03SP Praneesh static inline u32 ath11k_dp_rxdesc_get_mpdulen_err(struct rx_attention *attn) 248d5c65159SKalle Valo { 249d5c65159SKalle Valo return FIELD_GET(RX_ATTENTION_INFO1_MPDU_LEN_ERR, 250e678fbd4SKarthikeyan Periyasamy __le32_to_cpu(attn->info1)); 251d5c65159SKalle Valo } 252d5c65159SKalle Valo 2535e76fe03SP Praneesh static inline u8 *ath11k_dp_rxdesc_get_80211hdr(struct ath11k_base *ab, 254e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *rx_desc) 255d5c65159SKalle Valo { 256d5c65159SKalle Valo u8 *rx_pkt_hdr; 257d5c65159SKalle Valo 258e678fbd4SKarthikeyan Periyasamy rx_pkt_hdr = ab->hw_params.hw_ops->rx_desc_get_msdu_payload(rx_desc); 259d5c65159SKalle Valo 260d5c65159SKalle Valo return rx_pkt_hdr; 261d5c65159SKalle Valo } 262d5c65159SKalle Valo 2635e76fe03SP Praneesh static inline bool ath11k_dp_rxdesc_mpdu_valid(struct ath11k_base *ab, 264e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *rx_desc) 265d5c65159SKalle Valo { 266d5c65159SKalle Valo u32 tlv_tag; 267d5c65159SKalle Valo 268e678fbd4SKarthikeyan Periyasamy tlv_tag = ab->hw_params.hw_ops->rx_desc_get_mpdu_start_tag(rx_desc); 269d5c65159SKalle Valo 2708af40902SJason Yan return tlv_tag == HAL_RX_MPDU_START; 271d5c65159SKalle Valo } 272d5c65159SKalle Valo 2735e76fe03SP Praneesh static inline u32 ath11k_dp_rxdesc_get_ppduid(struct ath11k_base *ab, 274e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *rx_desc) 275d5c65159SKalle Valo { 276e678fbd4SKarthikeyan Periyasamy return ab->hw_params.hw_ops->rx_desc_get_mpdu_ppdu_id(rx_desc); 277e678fbd4SKarthikeyan Periyasamy } 278e678fbd4SKarthikeyan Periyasamy 2795e76fe03SP Praneesh static inline void ath11k_dp_rxdesc_set_msdu_len(struct ath11k_base *ab, 280e678fbd4SKarthikeyan Periyasamy struct hal_rx_desc *desc, 281e678fbd4SKarthikeyan Periyasamy u16 len) 282e678fbd4SKarthikeyan Periyasamy { 283e678fbd4SKarthikeyan Periyasamy ab->hw_params.hw_ops->rx_desc_set_msdu_len(desc, len); 284d5c65159SKalle Valo } 285d5c65159SKalle Valo 286210f563bSSriram R static bool ath11k_dp_rx_h_attn_is_mcbc(struct ath11k_base *ab, 287210f563bSSriram R struct hal_rx_desc *desc) 288210f563bSSriram R { 289210f563bSSriram R struct rx_attention *attn = ath11k_dp_rx_get_attention(ab, desc); 290210f563bSSriram R 291210f563bSSriram R return ath11k_dp_rx_h_msdu_end_first_msdu(ab, desc) && 292210f563bSSriram R (!!FIELD_GET(RX_ATTENTION_INFO1_MCAST_BCAST, 293210f563bSSriram R __le32_to_cpu(attn->info1))); 294210f563bSSriram R } 295210f563bSSriram R 2962167fa60SSriram R static bool ath11k_dp_rxdesc_mac_addr2_valid(struct ath11k_base *ab, 2972167fa60SSriram R struct hal_rx_desc *desc) 2982167fa60SSriram R { 2992167fa60SSriram R return ab->hw_params.hw_ops->rx_desc_mac_addr2_valid(desc); 3002167fa60SSriram R } 3012167fa60SSriram R 3022167fa60SSriram R static u8 *ath11k_dp_rxdesc_mpdu_start_addr2(struct ath11k_base *ab, 3032167fa60SSriram R struct hal_rx_desc *desc) 3042167fa60SSriram R { 3052167fa60SSriram R return ab->hw_params.hw_ops->rx_desc_mpdu_start_addr2(desc); 3062167fa60SSriram R } 3072167fa60SSriram R 308701e48a4SCarl Huang static void ath11k_dp_service_mon_ring(struct timer_list *t) 309701e48a4SCarl Huang { 310701e48a4SCarl Huang struct ath11k_base *ab = from_timer(ab, t, mon_reap_timer); 311701e48a4SCarl Huang int i; 312701e48a4SCarl Huang 313701e48a4SCarl Huang for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) 314701e48a4SCarl Huang ath11k_dp_rx_process_mon_rings(ab, i, NULL, DP_MON_SERVICE_BUDGET); 315701e48a4SCarl Huang 316701e48a4SCarl Huang mod_timer(&ab->mon_reap_timer, jiffies + 317701e48a4SCarl Huang msecs_to_jiffies(ATH11K_MON_TIMER_INTERVAL)); 318701e48a4SCarl Huang } 319701e48a4SCarl Huang 320840c36faSCarl Huang static int ath11k_dp_purge_mon_ring(struct ath11k_base *ab) 321840c36faSCarl Huang { 322840c36faSCarl Huang int i, reaped = 0; 323840c36faSCarl Huang unsigned long timeout = jiffies + msecs_to_jiffies(DP_MON_PURGE_TIMEOUT_MS); 324840c36faSCarl Huang 325840c36faSCarl Huang do { 326840c36faSCarl Huang for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) 327840c36faSCarl Huang reaped += ath11k_dp_rx_process_mon_rings(ab, i, 328840c36faSCarl Huang NULL, 329840c36faSCarl Huang DP_MON_SERVICE_BUDGET); 330840c36faSCarl Huang 331840c36faSCarl Huang /* nothing more to reap */ 332840c36faSCarl Huang if (reaped < DP_MON_SERVICE_BUDGET) 333840c36faSCarl Huang return 0; 334840c36faSCarl Huang 335840c36faSCarl Huang } while (time_before(jiffies, timeout)); 336840c36faSCarl Huang 337840c36faSCarl Huang ath11k_warn(ab, "dp mon ring purge timeout"); 338840c36faSCarl Huang 339840c36faSCarl Huang return -ETIMEDOUT; 340840c36faSCarl Huang } 341840c36faSCarl Huang 342d5c65159SKalle Valo /* Returns number of Rx buffers replenished */ 343d5c65159SKalle Valo int ath11k_dp_rxbufs_replenish(struct ath11k_base *ab, int mac_id, 344d5c65159SKalle Valo struct dp_rxdma_ring *rx_ring, 345d5c65159SKalle Valo int req_entries, 34687e8497aSGovind Singh enum hal_rx_buf_return_buf_manager mgr) 347d5c65159SKalle Valo { 348d5c65159SKalle Valo struct hal_srng *srng; 349d5c65159SKalle Valo u32 *desc; 350d5c65159SKalle Valo struct sk_buff *skb; 351d5c65159SKalle Valo int num_free; 352d5c65159SKalle Valo int num_remain; 353d5c65159SKalle Valo int buf_id; 354d5c65159SKalle Valo u32 cookie; 355d5c65159SKalle Valo dma_addr_t paddr; 356d5c65159SKalle Valo 357d5c65159SKalle Valo req_entries = min(req_entries, rx_ring->bufs_max); 358d5c65159SKalle Valo 359d5c65159SKalle Valo srng = &ab->hal.srng_list[rx_ring->refill_buf_ring.ring_id]; 360d5c65159SKalle Valo 361d5c65159SKalle Valo spin_lock_bh(&srng->lock); 362d5c65159SKalle Valo 363d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 364d5c65159SKalle Valo 365d5c65159SKalle Valo num_free = ath11k_hal_srng_src_num_free(ab, srng, true); 366d5c65159SKalle Valo if (!req_entries && (num_free > (rx_ring->bufs_max * 3) / 4)) 367d5c65159SKalle Valo req_entries = num_free; 368d5c65159SKalle Valo 369d5c65159SKalle Valo req_entries = min(num_free, req_entries); 370d5c65159SKalle Valo num_remain = req_entries; 371d5c65159SKalle Valo 372d5c65159SKalle Valo while (num_remain > 0) { 373d5c65159SKalle Valo skb = dev_alloc_skb(DP_RX_BUFFER_SIZE + 374d5c65159SKalle Valo DP_RX_BUFFER_ALIGN_SIZE); 375d5c65159SKalle Valo if (!skb) 376d5c65159SKalle Valo break; 377d5c65159SKalle Valo 378d5c65159SKalle Valo if (!IS_ALIGNED((unsigned long)skb->data, 379d5c65159SKalle Valo DP_RX_BUFFER_ALIGN_SIZE)) { 380d5c65159SKalle Valo skb_pull(skb, 381d5c65159SKalle Valo PTR_ALIGN(skb->data, DP_RX_BUFFER_ALIGN_SIZE) - 382d5c65159SKalle Valo skb->data); 383d5c65159SKalle Valo } 384d5c65159SKalle Valo 385d5c65159SKalle Valo paddr = dma_map_single(ab->dev, skb->data, 386d5c65159SKalle Valo skb->len + skb_tailroom(skb), 387d5c65159SKalle Valo DMA_FROM_DEVICE); 388d5c65159SKalle Valo if (dma_mapping_error(ab->dev, paddr)) 389d5c65159SKalle Valo goto fail_free_skb; 390d5c65159SKalle Valo 391d5c65159SKalle Valo spin_lock_bh(&rx_ring->idr_lock); 392f9fff67dSNagarajan Maran buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 1, 393f9fff67dSNagarajan Maran (rx_ring->bufs_max * 3) + 1, GFP_ATOMIC); 394d5c65159SKalle Valo spin_unlock_bh(&rx_ring->idr_lock); 395f9fff67dSNagarajan Maran if (buf_id <= 0) 396d5c65159SKalle Valo goto fail_dma_unmap; 397d5c65159SKalle Valo 398d5c65159SKalle Valo desc = ath11k_hal_srng_src_get_next_entry(ab, srng); 399d5c65159SKalle Valo if (!desc) 400d5c65159SKalle Valo goto fail_idr_remove; 401d5c65159SKalle Valo 402d5c65159SKalle Valo ATH11K_SKB_RXCB(skb)->paddr = paddr; 403d5c65159SKalle Valo 404d5c65159SKalle Valo cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, mac_id) | 405d5c65159SKalle Valo FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id); 406d5c65159SKalle Valo 407d5c65159SKalle Valo num_remain--; 408d5c65159SKalle Valo 409d5c65159SKalle Valo ath11k_hal_rx_buf_addr_info_set(desc, paddr, cookie, mgr); 410d5c65159SKalle Valo } 411d5c65159SKalle Valo 412d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 413d5c65159SKalle Valo 414d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 415d5c65159SKalle Valo 416d5c65159SKalle Valo return req_entries - num_remain; 417d5c65159SKalle Valo 418d5c65159SKalle Valo fail_idr_remove: 419d5c65159SKalle Valo spin_lock_bh(&rx_ring->idr_lock); 420d5c65159SKalle Valo idr_remove(&rx_ring->bufs_idr, buf_id); 421d5c65159SKalle Valo spin_unlock_bh(&rx_ring->idr_lock); 422d5c65159SKalle Valo fail_dma_unmap: 423d5c65159SKalle Valo dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb), 424d5c65159SKalle Valo DMA_FROM_DEVICE); 425d5c65159SKalle Valo fail_free_skb: 426d5c65159SKalle Valo dev_kfree_skb_any(skb); 427d5c65159SKalle Valo 428d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 429d5c65159SKalle Valo 430d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 431d5c65159SKalle Valo 432d5c65159SKalle Valo return req_entries - num_remain; 433d5c65159SKalle Valo } 434d5c65159SKalle Valo 435d5c65159SKalle Valo static int ath11k_dp_rxdma_buf_ring_free(struct ath11k *ar, 436d5c65159SKalle Valo struct dp_rxdma_ring *rx_ring) 437d5c65159SKalle Valo { 438d5c65159SKalle Valo struct sk_buff *skb; 439d5c65159SKalle Valo int buf_id; 440d5c65159SKalle Valo 441d5c65159SKalle Valo spin_lock_bh(&rx_ring->idr_lock); 442d5c65159SKalle Valo idr_for_each_entry(&rx_ring->bufs_idr, skb, buf_id) { 443d5c65159SKalle Valo idr_remove(&rx_ring->bufs_idr, buf_id); 44416f283f0SKalle Valo /* TODO: Understand where internal driver does this dma_unmap 445d5c65159SKalle Valo * of rxdma_buffer. 446d5c65159SKalle Valo */ 447d5c65159SKalle Valo dma_unmap_single(ar->ab->dev, ATH11K_SKB_RXCB(skb)->paddr, 448d5c65159SKalle Valo skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); 449d5c65159SKalle Valo dev_kfree_skb_any(skb); 450d5c65159SKalle Valo } 451d5c65159SKalle Valo 452d5c65159SKalle Valo idr_destroy(&rx_ring->bufs_idr); 453d5c65159SKalle Valo spin_unlock_bh(&rx_ring->idr_lock); 454d5c65159SKalle Valo 455d5c65159SKalle Valo return 0; 456d5c65159SKalle Valo } 457d5c65159SKalle Valo 458d5c65159SKalle Valo static int ath11k_dp_rxdma_pdev_buf_free(struct ath11k *ar) 459d5c65159SKalle Valo { 460d5c65159SKalle Valo struct ath11k_pdev_dp *dp = &ar->dp; 4614152e420SCarl Huang struct ath11k_base *ab = ar->ab; 462d5c65159SKalle Valo struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; 4634152e420SCarl Huang int i; 464d5c65159SKalle Valo 465d5c65159SKalle Valo ath11k_dp_rxdma_buf_ring_free(ar, rx_ring); 466d5c65159SKalle Valo 467d5c65159SKalle Valo rx_ring = &dp->rxdma_mon_buf_ring; 468d5c65159SKalle Valo ath11k_dp_rxdma_buf_ring_free(ar, rx_ring); 469d5c65159SKalle Valo 4704152e420SCarl Huang for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { 4714152e420SCarl Huang rx_ring = &dp->rx_mon_status_refill_ring[i]; 472d5c65159SKalle Valo ath11k_dp_rxdma_buf_ring_free(ar, rx_ring); 4734152e420SCarl Huang } 4744152e420SCarl Huang 475d5c65159SKalle Valo return 0; 476d5c65159SKalle Valo } 477d5c65159SKalle Valo 478d5c65159SKalle Valo static int ath11k_dp_rxdma_ring_buf_setup(struct ath11k *ar, 479d5c65159SKalle Valo struct dp_rxdma_ring *rx_ring, 480d5c65159SKalle Valo u32 ringtype) 481d5c65159SKalle Valo { 482d5c65159SKalle Valo struct ath11k_pdev_dp *dp = &ar->dp; 483d5c65159SKalle Valo int num_entries; 484d5c65159SKalle Valo 485d5c65159SKalle Valo num_entries = rx_ring->refill_buf_ring.size / 486f7eb4b04SKalle Valo ath11k_hal_srng_get_entrysize(ar->ab, ringtype); 487d5c65159SKalle Valo 488d5c65159SKalle Valo rx_ring->bufs_max = num_entries; 489d5c65159SKalle Valo ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, rx_ring, num_entries, 490734223d7SBaochen Qiang ar->ab->hw_params.hal_params->rx_buf_rbm); 491d5c65159SKalle Valo return 0; 492d5c65159SKalle Valo } 493d5c65159SKalle Valo 494d5c65159SKalle Valo static int ath11k_dp_rxdma_pdev_buf_setup(struct ath11k *ar) 495d5c65159SKalle Valo { 496d5c65159SKalle Valo struct ath11k_pdev_dp *dp = &ar->dp; 4974152e420SCarl Huang struct ath11k_base *ab = ar->ab; 498d5c65159SKalle Valo struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; 4994152e420SCarl Huang int i; 500d5c65159SKalle Valo 501d5c65159SKalle Valo ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_BUF); 502d5c65159SKalle Valo 5037f6fc1ebSCarl Huang if (ar->ab->hw_params.rxdma1_enable) { 504d5c65159SKalle Valo rx_ring = &dp->rxdma_mon_buf_ring; 505d5c65159SKalle Valo ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_BUF); 5067f6fc1ebSCarl Huang } 507d5c65159SKalle Valo 5084152e420SCarl Huang for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { 5094152e420SCarl Huang rx_ring = &dp->rx_mon_status_refill_ring[i]; 510d5c65159SKalle Valo ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_STATUS); 5114152e420SCarl Huang } 512d5c65159SKalle Valo 513d5c65159SKalle Valo return 0; 514d5c65159SKalle Valo } 515d5c65159SKalle Valo 516d5c65159SKalle Valo static void ath11k_dp_rx_pdev_srng_free(struct ath11k *ar) 517d5c65159SKalle Valo { 518d5c65159SKalle Valo struct ath11k_pdev_dp *dp = &ar->dp; 5194152e420SCarl Huang struct ath11k_base *ab = ar->ab; 5204152e420SCarl Huang int i; 521d5c65159SKalle Valo 5224152e420SCarl Huang ath11k_dp_srng_cleanup(ab, &dp->rx_refill_buf_ring.refill_buf_ring); 5234152e420SCarl Huang 5244152e420SCarl Huang for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { 5254152e420SCarl Huang if (ab->hw_params.rx_mac_buf_ring) 5264152e420SCarl Huang ath11k_dp_srng_cleanup(ab, &dp->rx_mac_buf_ring[i]); 5274152e420SCarl Huang 5284152e420SCarl Huang ath11k_dp_srng_cleanup(ab, &dp->rxdma_err_dst_ring[i]); 5294152e420SCarl Huang ath11k_dp_srng_cleanup(ab, 5304152e420SCarl Huang &dp->rx_mon_status_refill_ring[i].refill_buf_ring); 5314152e420SCarl Huang } 5324152e420SCarl Huang 5334152e420SCarl Huang ath11k_dp_srng_cleanup(ab, &dp->rxdma_mon_buf_ring.refill_buf_ring); 534d5c65159SKalle Valo } 535d5c65159SKalle Valo 5369c57d7e3SVasanthakumar Thiagarajan void ath11k_dp_pdev_reo_cleanup(struct ath11k_base *ab) 5379c57d7e3SVasanthakumar Thiagarajan { 538acc79d98SSriram R struct ath11k_dp *dp = &ab->dp; 5399c57d7e3SVasanthakumar Thiagarajan int i; 5409c57d7e3SVasanthakumar Thiagarajan 541acc79d98SSriram R for (i = 0; i < DP_REO_DST_RING_MAX; i++) 542acc79d98SSriram R ath11k_dp_srng_cleanup(ab, &dp->reo_dst_ring[i]); 5439c57d7e3SVasanthakumar Thiagarajan } 5449c57d7e3SVasanthakumar Thiagarajan 5459c57d7e3SVasanthakumar Thiagarajan int ath11k_dp_pdev_reo_setup(struct ath11k_base *ab) 5469c57d7e3SVasanthakumar Thiagarajan { 547acc79d98SSriram R struct ath11k_dp *dp = &ab->dp; 5489c57d7e3SVasanthakumar Thiagarajan int ret; 5499c57d7e3SVasanthakumar Thiagarajan int i; 5509c57d7e3SVasanthakumar Thiagarajan 551acc79d98SSriram R for (i = 0; i < DP_REO_DST_RING_MAX; i++) { 552acc79d98SSriram R ret = ath11k_dp_srng_setup(ab, &dp->reo_dst_ring[i], 553acc79d98SSriram R HAL_REO_DST, i, 0, 5549c57d7e3SVasanthakumar Thiagarajan DP_REO_DST_RING_SIZE); 5559c57d7e3SVasanthakumar Thiagarajan if (ret) { 556acc79d98SSriram R ath11k_warn(ab, "failed to setup reo_dst_ring\n"); 5579c57d7e3SVasanthakumar Thiagarajan goto err_reo_cleanup; 5589c57d7e3SVasanthakumar Thiagarajan } 5599c57d7e3SVasanthakumar Thiagarajan } 5609c57d7e3SVasanthakumar Thiagarajan 5619c57d7e3SVasanthakumar Thiagarajan return 0; 5629c57d7e3SVasanthakumar Thiagarajan 5639c57d7e3SVasanthakumar Thiagarajan err_reo_cleanup: 5649c57d7e3SVasanthakumar Thiagarajan ath11k_dp_pdev_reo_cleanup(ab); 5659c57d7e3SVasanthakumar Thiagarajan 5669c57d7e3SVasanthakumar Thiagarajan return ret; 5679c57d7e3SVasanthakumar Thiagarajan } 5689c57d7e3SVasanthakumar Thiagarajan 569d5c65159SKalle Valo static int ath11k_dp_rx_pdev_srng_alloc(struct ath11k *ar) 570d5c65159SKalle Valo { 571d5c65159SKalle Valo struct ath11k_pdev_dp *dp = &ar->dp; 5724152e420SCarl Huang struct ath11k_base *ab = ar->ab; 573d5c65159SKalle Valo struct dp_srng *srng = NULL; 5744152e420SCarl Huang int i; 575d5c65159SKalle Valo int ret; 576d5c65159SKalle Valo 577d5c65159SKalle Valo ret = ath11k_dp_srng_setup(ar->ab, 578d5c65159SKalle Valo &dp->rx_refill_buf_ring.refill_buf_ring, 579d5c65159SKalle Valo HAL_RXDMA_BUF, 0, 580d5c65159SKalle Valo dp->mac_id, DP_RXDMA_BUF_RING_SIZE); 581d5c65159SKalle Valo if (ret) { 582d5c65159SKalle Valo ath11k_warn(ar->ab, "failed to setup rx_refill_buf_ring\n"); 583d5c65159SKalle Valo return ret; 584d5c65159SKalle Valo } 585d5c65159SKalle Valo 5864152e420SCarl Huang if (ar->ab->hw_params.rx_mac_buf_ring) { 5874152e420SCarl Huang for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { 5884152e420SCarl Huang ret = ath11k_dp_srng_setup(ar->ab, 5894152e420SCarl Huang &dp->rx_mac_buf_ring[i], 5904152e420SCarl Huang HAL_RXDMA_BUF, 1, 5914152e420SCarl Huang dp->mac_id + i, 1024); 592d5c65159SKalle Valo if (ret) { 5934152e420SCarl Huang ath11k_warn(ar->ab, "failed to setup rx_mac_buf_ring %d\n", 5944152e420SCarl Huang i); 595d5c65159SKalle Valo return ret; 596d5c65159SKalle Valo } 5974152e420SCarl Huang } 5984152e420SCarl Huang } 599d5c65159SKalle Valo 6004152e420SCarl Huang for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { 6014152e420SCarl Huang ret = ath11k_dp_srng_setup(ar->ab, &dp->rxdma_err_dst_ring[i], 6024152e420SCarl Huang HAL_RXDMA_DST, 0, dp->mac_id + i, 6034152e420SCarl Huang DP_RXDMA_ERR_DST_RING_SIZE); 6044152e420SCarl Huang if (ret) { 6054152e420SCarl Huang ath11k_warn(ar->ab, "failed to setup rxdma_err_dst_ring %d\n", i); 6064152e420SCarl Huang return ret; 6074152e420SCarl Huang } 6084152e420SCarl Huang } 6094152e420SCarl Huang 6104152e420SCarl Huang for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { 6114152e420SCarl Huang srng = &dp->rx_mon_status_refill_ring[i].refill_buf_ring; 612d5c65159SKalle Valo ret = ath11k_dp_srng_setup(ar->ab, 613d5c65159SKalle Valo srng, 6144152e420SCarl Huang HAL_RXDMA_MONITOR_STATUS, 0, dp->mac_id + i, 615d5c65159SKalle Valo DP_RXDMA_MON_STATUS_RING_SIZE); 616d5c65159SKalle Valo if (ret) { 617d5c65159SKalle Valo ath11k_warn(ar->ab, 6184152e420SCarl Huang "failed to setup rx_mon_status_refill_ring %d\n", i); 619d5c65159SKalle Valo return ret; 620d5c65159SKalle Valo } 6214152e420SCarl Huang } 6227f6fc1ebSCarl Huang 6237f6fc1ebSCarl Huang /* if rxdma1_enable is false, then it doesn't need 6247f6fc1ebSCarl Huang * to setup rxdam_mon_buf_ring, rxdma_mon_dst_ring 6257f6fc1ebSCarl Huang * and rxdma_mon_desc_ring. 626701e48a4SCarl Huang * init reap timer for QCA6390. 6277f6fc1ebSCarl Huang */ 628701e48a4SCarl Huang if (!ar->ab->hw_params.rxdma1_enable) { 629701e48a4SCarl Huang //init mon status buffer reap timer 630701e48a4SCarl Huang timer_setup(&ar->ab->mon_reap_timer, 631701e48a4SCarl Huang ath11k_dp_service_mon_ring, 0); 6327f6fc1ebSCarl Huang return 0; 633701e48a4SCarl Huang } 6347f6fc1ebSCarl Huang 635d5c65159SKalle Valo ret = ath11k_dp_srng_setup(ar->ab, 636d5c65159SKalle Valo &dp->rxdma_mon_buf_ring.refill_buf_ring, 637d5c65159SKalle Valo HAL_RXDMA_MONITOR_BUF, 0, dp->mac_id, 638d5c65159SKalle Valo DP_RXDMA_MONITOR_BUF_RING_SIZE); 639d5c65159SKalle Valo if (ret) { 640d5c65159SKalle Valo ath11k_warn(ar->ab, 641d5c65159SKalle Valo "failed to setup HAL_RXDMA_MONITOR_BUF\n"); 642d5c65159SKalle Valo return ret; 643d5c65159SKalle Valo } 644d5c65159SKalle Valo 645d5c65159SKalle Valo ret = ath11k_dp_srng_setup(ar->ab, &dp->rxdma_mon_dst_ring, 646d5c65159SKalle Valo HAL_RXDMA_MONITOR_DST, 0, dp->mac_id, 647d5c65159SKalle Valo DP_RXDMA_MONITOR_DST_RING_SIZE); 648d5c65159SKalle Valo if (ret) { 649d5c65159SKalle Valo ath11k_warn(ar->ab, 650d5c65159SKalle Valo "failed to setup HAL_RXDMA_MONITOR_DST\n"); 651d5c65159SKalle Valo return ret; 652d5c65159SKalle Valo } 653d5c65159SKalle Valo 654d5c65159SKalle Valo ret = ath11k_dp_srng_setup(ar->ab, &dp->rxdma_mon_desc_ring, 655d5c65159SKalle Valo HAL_RXDMA_MONITOR_DESC, 0, dp->mac_id, 656d5c65159SKalle Valo DP_RXDMA_MONITOR_DESC_RING_SIZE); 657d5c65159SKalle Valo if (ret) { 658d5c65159SKalle Valo ath11k_warn(ar->ab, 659d5c65159SKalle Valo "failed to setup HAL_RXDMA_MONITOR_DESC\n"); 660d5c65159SKalle Valo return ret; 661d5c65159SKalle Valo } 662d5c65159SKalle Valo 663d5c65159SKalle Valo return 0; 664d5c65159SKalle Valo } 665d5c65159SKalle Valo 666d5c65159SKalle Valo void ath11k_dp_reo_cmd_list_cleanup(struct ath11k_base *ab) 667d5c65159SKalle Valo { 668d5c65159SKalle Valo struct ath11k_dp *dp = &ab->dp; 669d5c65159SKalle Valo struct dp_reo_cmd *cmd, *tmp; 670d5c65159SKalle Valo struct dp_reo_cache_flush_elem *cmd_cache, *tmp_cache; 67193a91f40SHarshitha Prem struct dp_rx_tid *rx_tid; 672d5c65159SKalle Valo 673d5c65159SKalle Valo spin_lock_bh(&dp->reo_cmd_lock); 674d5c65159SKalle Valo list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) { 675d5c65159SKalle Valo list_del(&cmd->list); 67693a91f40SHarshitha Prem rx_tid = &cmd->data; 67793a91f40SHarshitha Prem if (rx_tid->vaddr) { 67893a91f40SHarshitha Prem dma_unmap_single(ab->dev, rx_tid->paddr, 67993a91f40SHarshitha Prem rx_tid->size, DMA_BIDIRECTIONAL); 68093a91f40SHarshitha Prem kfree(rx_tid->vaddr); 68193a91f40SHarshitha Prem rx_tid->vaddr = NULL; 68293a91f40SHarshitha Prem } 683d5c65159SKalle Valo kfree(cmd); 684d5c65159SKalle Valo } 685d5c65159SKalle Valo 686d5c65159SKalle Valo list_for_each_entry_safe(cmd_cache, tmp_cache, 687d5c65159SKalle Valo &dp->reo_cmd_cache_flush_list, list) { 688d5c65159SKalle Valo list_del(&cmd_cache->list); 6895cb899ddSKarthikeyan Periyasamy dp->reo_cmd_cache_flush_count--; 69093a91f40SHarshitha Prem rx_tid = &cmd_cache->data; 69193a91f40SHarshitha Prem if (rx_tid->vaddr) { 69293a91f40SHarshitha Prem dma_unmap_single(ab->dev, rx_tid->paddr, 69393a91f40SHarshitha Prem rx_tid->size, DMA_BIDIRECTIONAL); 69493a91f40SHarshitha Prem kfree(rx_tid->vaddr); 69593a91f40SHarshitha Prem rx_tid->vaddr = NULL; 69693a91f40SHarshitha Prem } 697d5c65159SKalle Valo kfree(cmd_cache); 698d5c65159SKalle Valo } 699d5c65159SKalle Valo spin_unlock_bh(&dp->reo_cmd_lock); 700d5c65159SKalle Valo } 701d5c65159SKalle Valo 702d5c65159SKalle Valo static void ath11k_dp_reo_cmd_free(struct ath11k_dp *dp, void *ctx, 703d5c65159SKalle Valo enum hal_reo_cmd_status status) 704d5c65159SKalle Valo { 705d5c65159SKalle Valo struct dp_rx_tid *rx_tid = ctx; 706d5c65159SKalle Valo 707d5c65159SKalle Valo if (status != HAL_REO_CMD_SUCCESS) 708d5c65159SKalle Valo ath11k_warn(dp->ab, "failed to flush rx tid hw desc, tid %d status %d\n", 709d5c65159SKalle Valo rx_tid->tid, status); 71093a91f40SHarshitha Prem if (rx_tid->vaddr) { 711d5c65159SKalle Valo dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size, 712d5c65159SKalle Valo DMA_BIDIRECTIONAL); 713d5c65159SKalle Valo kfree(rx_tid->vaddr); 71493a91f40SHarshitha Prem rx_tid->vaddr = NULL; 71593a91f40SHarshitha Prem } 716d5c65159SKalle Valo } 717d5c65159SKalle Valo 718d5c65159SKalle Valo static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab, 719d5c65159SKalle Valo struct dp_rx_tid *rx_tid) 720d5c65159SKalle Valo { 721d5c65159SKalle Valo struct ath11k_hal_reo_cmd cmd = {0}; 722d5c65159SKalle Valo unsigned long tot_desc_sz, desc_sz; 723d5c65159SKalle Valo int ret; 724d5c65159SKalle Valo 725d5c65159SKalle Valo tot_desc_sz = rx_tid->size; 726d5c65159SKalle Valo desc_sz = ath11k_hal_reo_qdesc_size(0, HAL_DESC_REO_NON_QOS_TID); 727d5c65159SKalle Valo 728d5c65159SKalle Valo while (tot_desc_sz > desc_sz) { 729d5c65159SKalle Valo tot_desc_sz -= desc_sz; 730d5c65159SKalle Valo cmd.addr_lo = lower_32_bits(rx_tid->paddr + tot_desc_sz); 731d5c65159SKalle Valo cmd.addr_hi = upper_32_bits(rx_tid->paddr); 732d5c65159SKalle Valo ret = ath11k_dp_tx_send_reo_cmd(ab, rx_tid, 733d5c65159SKalle Valo HAL_REO_CMD_FLUSH_CACHE, &cmd, 734d5c65159SKalle Valo NULL); 735d5c65159SKalle Valo if (ret) 736d5c65159SKalle Valo ath11k_warn(ab, 737d5c65159SKalle Valo "failed to send HAL_REO_CMD_FLUSH_CACHE, tid %d (%d)\n", 738d5c65159SKalle Valo rx_tid->tid, ret); 739d5c65159SKalle Valo } 740d5c65159SKalle Valo 741d5c65159SKalle Valo memset(&cmd, 0, sizeof(cmd)); 742d5c65159SKalle Valo cmd.addr_lo = lower_32_bits(rx_tid->paddr); 743d5c65159SKalle Valo cmd.addr_hi = upper_32_bits(rx_tid->paddr); 744d5c65159SKalle Valo cmd.flag |= HAL_REO_CMD_FLG_NEED_STATUS; 745d5c65159SKalle Valo ret = ath11k_dp_tx_send_reo_cmd(ab, rx_tid, 746d5c65159SKalle Valo HAL_REO_CMD_FLUSH_CACHE, 747d5c65159SKalle Valo &cmd, ath11k_dp_reo_cmd_free); 748d5c65159SKalle Valo if (ret) { 749d5c65159SKalle Valo ath11k_err(ab, "failed to send HAL_REO_CMD_FLUSH_CACHE cmd, tid %d (%d)\n", 750d5c65159SKalle Valo rx_tid->tid, ret); 751d5c65159SKalle Valo dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size, 752d5c65159SKalle Valo DMA_BIDIRECTIONAL); 753d5c65159SKalle Valo kfree(rx_tid->vaddr); 75493a91f40SHarshitha Prem rx_tid->vaddr = NULL; 755d5c65159SKalle Valo } 756d5c65159SKalle Valo } 757d5c65159SKalle Valo 758d5c65159SKalle Valo static void ath11k_dp_rx_tid_del_func(struct ath11k_dp *dp, void *ctx, 759d5c65159SKalle Valo enum hal_reo_cmd_status status) 760d5c65159SKalle Valo { 761d5c65159SKalle Valo struct ath11k_base *ab = dp->ab; 762d5c65159SKalle Valo struct dp_rx_tid *rx_tid = ctx; 763d5c65159SKalle Valo struct dp_reo_cache_flush_elem *elem, *tmp; 764d5c65159SKalle Valo 765d5c65159SKalle Valo if (status == HAL_REO_CMD_DRAIN) { 766d5c65159SKalle Valo goto free_desc; 767d5c65159SKalle Valo } else if (status != HAL_REO_CMD_SUCCESS) { 768d5c65159SKalle Valo /* Shouldn't happen! Cleanup in case of other failure? */ 769d5c65159SKalle Valo ath11k_warn(ab, "failed to delete rx tid %d hw descriptor %d\n", 770d5c65159SKalle Valo rx_tid->tid, status); 771d5c65159SKalle Valo return; 772d5c65159SKalle Valo } 773d5c65159SKalle Valo 774d5c65159SKalle Valo elem = kzalloc(sizeof(*elem), GFP_ATOMIC); 775d5c65159SKalle Valo if (!elem) 776d5c65159SKalle Valo goto free_desc; 777d5c65159SKalle Valo 778d5c65159SKalle Valo elem->ts = jiffies; 779d5c65159SKalle Valo memcpy(&elem->data, rx_tid, sizeof(*rx_tid)); 780d5c65159SKalle Valo 781d5c65159SKalle Valo spin_lock_bh(&dp->reo_cmd_lock); 782d5c65159SKalle Valo list_add_tail(&elem->list, &dp->reo_cmd_cache_flush_list); 7835cb899ddSKarthikeyan Periyasamy dp->reo_cmd_cache_flush_count++; 784d5c65159SKalle Valo 785d5c65159SKalle Valo /* Flush and invalidate aged REO desc from HW cache */ 786d5c65159SKalle Valo list_for_each_entry_safe(elem, tmp, &dp->reo_cmd_cache_flush_list, 787d5c65159SKalle Valo list) { 7885cb899ddSKarthikeyan Periyasamy if (dp->reo_cmd_cache_flush_count > DP_REO_DESC_FREE_THRESHOLD || 7895cb899ddSKarthikeyan Periyasamy time_after(jiffies, elem->ts + 790d5c65159SKalle Valo msecs_to_jiffies(DP_REO_DESC_FREE_TIMEOUT_MS))) { 791d5c65159SKalle Valo list_del(&elem->list); 7925cb899ddSKarthikeyan Periyasamy dp->reo_cmd_cache_flush_count--; 793d5c65159SKalle Valo spin_unlock_bh(&dp->reo_cmd_lock); 794d5c65159SKalle Valo 795d5c65159SKalle Valo ath11k_dp_reo_cache_flush(ab, &elem->data); 796d5c65159SKalle Valo kfree(elem); 797d5c65159SKalle Valo spin_lock_bh(&dp->reo_cmd_lock); 798d5c65159SKalle Valo } 799d5c65159SKalle Valo } 800d5c65159SKalle Valo spin_unlock_bh(&dp->reo_cmd_lock); 801d5c65159SKalle Valo 802d5c65159SKalle Valo return; 803d5c65159SKalle Valo free_desc: 804d5c65159SKalle Valo dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size, 805d5c65159SKalle Valo DMA_BIDIRECTIONAL); 806d5c65159SKalle Valo kfree(rx_tid->vaddr); 80793a91f40SHarshitha Prem rx_tid->vaddr = NULL; 808d5c65159SKalle Valo } 809d5c65159SKalle Valo 810a36adf54SGovindaraj Saminathan void ath11k_peer_rx_tid_delete(struct ath11k *ar, 811d5c65159SKalle Valo struct ath11k_peer *peer, u8 tid) 812d5c65159SKalle Valo { 813d5c65159SKalle Valo struct ath11k_hal_reo_cmd cmd = {0}; 814d5c65159SKalle Valo struct dp_rx_tid *rx_tid = &peer->rx_tid[tid]; 815d5c65159SKalle Valo int ret; 816d5c65159SKalle Valo 817d5c65159SKalle Valo if (!rx_tid->active) 818d5c65159SKalle Valo return; 819d5c65159SKalle Valo 82093a91f40SHarshitha Prem rx_tid->active = false; 82193a91f40SHarshitha Prem 822d5c65159SKalle Valo cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS; 823d5c65159SKalle Valo cmd.addr_lo = lower_32_bits(rx_tid->paddr); 824d5c65159SKalle Valo cmd.addr_hi = upper_32_bits(rx_tid->paddr); 825d5c65159SKalle Valo cmd.upd0 |= HAL_REO_CMD_UPD0_VLD; 826d5c65159SKalle Valo ret = ath11k_dp_tx_send_reo_cmd(ar->ab, rx_tid, 827d5c65159SKalle Valo HAL_REO_CMD_UPDATE_RX_QUEUE, &cmd, 828d5c65159SKalle Valo ath11k_dp_rx_tid_del_func); 829d5c65159SKalle Valo if (ret) { 8300ab52b2bSManikanta Pubbisetty if (ret != -ESHUTDOWN) 831d5c65159SKalle Valo ath11k_err(ar->ab, "failed to send HAL_REO_CMD_UPDATE_RX_QUEUE cmd, tid %d (%d)\n", 832d5c65159SKalle Valo tid, ret); 833d5c65159SKalle Valo dma_unmap_single(ar->ab->dev, rx_tid->paddr, rx_tid->size, 834d5c65159SKalle Valo DMA_BIDIRECTIONAL); 835d5c65159SKalle Valo kfree(rx_tid->vaddr); 83693a91f40SHarshitha Prem rx_tid->vaddr = NULL; 837d5c65159SKalle Valo } 838d5c65159SKalle Valo 83993a91f40SHarshitha Prem rx_tid->paddr = 0; 84093a91f40SHarshitha Prem rx_tid->size = 0; 841d5c65159SKalle Valo } 842d5c65159SKalle Valo 843243874c6SManikanta Pubbisetty static int ath11k_dp_rx_link_desc_return(struct ath11k_base *ab, 844243874c6SManikanta Pubbisetty u32 *link_desc, 845243874c6SManikanta Pubbisetty enum hal_wbm_rel_bm_act action) 846243874c6SManikanta Pubbisetty { 847243874c6SManikanta Pubbisetty struct ath11k_dp *dp = &ab->dp; 848243874c6SManikanta Pubbisetty struct hal_srng *srng; 849243874c6SManikanta Pubbisetty u32 *desc; 850243874c6SManikanta Pubbisetty int ret = 0; 851243874c6SManikanta Pubbisetty 852243874c6SManikanta Pubbisetty srng = &ab->hal.srng_list[dp->wbm_desc_rel_ring.ring_id]; 853243874c6SManikanta Pubbisetty 854243874c6SManikanta Pubbisetty spin_lock_bh(&srng->lock); 855243874c6SManikanta Pubbisetty 856243874c6SManikanta Pubbisetty ath11k_hal_srng_access_begin(ab, srng); 857243874c6SManikanta Pubbisetty 858243874c6SManikanta Pubbisetty desc = ath11k_hal_srng_src_get_next_entry(ab, srng); 859243874c6SManikanta Pubbisetty if (!desc) { 860243874c6SManikanta Pubbisetty ret = -ENOBUFS; 861243874c6SManikanta Pubbisetty goto exit; 862243874c6SManikanta Pubbisetty } 863243874c6SManikanta Pubbisetty 864243874c6SManikanta Pubbisetty ath11k_hal_rx_msdu_link_desc_set(ab, (void *)desc, (void *)link_desc, 865243874c6SManikanta Pubbisetty action); 866243874c6SManikanta Pubbisetty 867243874c6SManikanta Pubbisetty exit: 868243874c6SManikanta Pubbisetty ath11k_hal_srng_access_end(ab, srng); 869243874c6SManikanta Pubbisetty 870243874c6SManikanta Pubbisetty spin_unlock_bh(&srng->lock); 871243874c6SManikanta Pubbisetty 872243874c6SManikanta Pubbisetty return ret; 873243874c6SManikanta Pubbisetty } 874243874c6SManikanta Pubbisetty 875243874c6SManikanta Pubbisetty static void ath11k_dp_rx_frags_cleanup(struct dp_rx_tid *rx_tid, bool rel_link_desc) 876243874c6SManikanta Pubbisetty { 877243874c6SManikanta Pubbisetty struct ath11k_base *ab = rx_tid->ab; 878243874c6SManikanta Pubbisetty 879243874c6SManikanta Pubbisetty lockdep_assert_held(&ab->base_lock); 880243874c6SManikanta Pubbisetty 881243874c6SManikanta Pubbisetty if (rx_tid->dst_ring_desc) { 882243874c6SManikanta Pubbisetty if (rel_link_desc) 883243874c6SManikanta Pubbisetty ath11k_dp_rx_link_desc_return(ab, (u32 *)rx_tid->dst_ring_desc, 884243874c6SManikanta Pubbisetty HAL_WBM_REL_BM_ACT_PUT_IN_IDLE); 885243874c6SManikanta Pubbisetty kfree(rx_tid->dst_ring_desc); 886243874c6SManikanta Pubbisetty rx_tid->dst_ring_desc = NULL; 887243874c6SManikanta Pubbisetty } 888243874c6SManikanta Pubbisetty 889243874c6SManikanta Pubbisetty rx_tid->cur_sn = 0; 890243874c6SManikanta Pubbisetty rx_tid->last_frag_no = 0; 891243874c6SManikanta Pubbisetty rx_tid->rx_frag_bitmap = 0; 892243874c6SManikanta Pubbisetty __skb_queue_purge(&rx_tid->rx_frags); 893243874c6SManikanta Pubbisetty } 894243874c6SManikanta Pubbisetty 895c3944a56SSriram R void ath11k_peer_frags_flush(struct ath11k *ar, struct ath11k_peer *peer) 896c3944a56SSriram R { 897c3944a56SSriram R struct dp_rx_tid *rx_tid; 898c3944a56SSriram R int i; 899c3944a56SSriram R 900c3944a56SSriram R lockdep_assert_held(&ar->ab->base_lock); 901c3944a56SSriram R 902c3944a56SSriram R for (i = 0; i <= IEEE80211_NUM_TIDS; i++) { 903c3944a56SSriram R rx_tid = &peer->rx_tid[i]; 904c3944a56SSriram R 905c3944a56SSriram R spin_unlock_bh(&ar->ab->base_lock); 906c3944a56SSriram R del_timer_sync(&rx_tid->frag_timer); 907c3944a56SSriram R spin_lock_bh(&ar->ab->base_lock); 908c3944a56SSriram R 909c3944a56SSriram R ath11k_dp_rx_frags_cleanup(rx_tid, true); 910c3944a56SSriram R } 911c3944a56SSriram R } 912c3944a56SSriram R 913d5c65159SKalle Valo void ath11k_peer_rx_tid_cleanup(struct ath11k *ar, struct ath11k_peer *peer) 914d5c65159SKalle Valo { 915243874c6SManikanta Pubbisetty struct dp_rx_tid *rx_tid; 916d5c65159SKalle Valo int i; 917d5c65159SKalle Valo 918243874c6SManikanta Pubbisetty lockdep_assert_held(&ar->ab->base_lock); 919243874c6SManikanta Pubbisetty 920243874c6SManikanta Pubbisetty for (i = 0; i <= IEEE80211_NUM_TIDS; i++) { 921243874c6SManikanta Pubbisetty rx_tid = &peer->rx_tid[i]; 922243874c6SManikanta Pubbisetty 923d5c65159SKalle Valo ath11k_peer_rx_tid_delete(ar, peer, i); 924243874c6SManikanta Pubbisetty ath11k_dp_rx_frags_cleanup(rx_tid, true); 925243874c6SManikanta Pubbisetty 926243874c6SManikanta Pubbisetty spin_unlock_bh(&ar->ab->base_lock); 927243874c6SManikanta Pubbisetty del_timer_sync(&rx_tid->frag_timer); 928243874c6SManikanta Pubbisetty spin_lock_bh(&ar->ab->base_lock); 929243874c6SManikanta Pubbisetty } 930d5c65159SKalle Valo } 931d5c65159SKalle Valo 932d5c65159SKalle Valo static int ath11k_peer_rx_tid_reo_update(struct ath11k *ar, 933d5c65159SKalle Valo struct ath11k_peer *peer, 934d5c65159SKalle Valo struct dp_rx_tid *rx_tid, 935fe201947SVenkateswara Naralasetty u32 ba_win_sz, u16 ssn, 936fe201947SVenkateswara Naralasetty bool update_ssn) 937d5c65159SKalle Valo { 938d5c65159SKalle Valo struct ath11k_hal_reo_cmd cmd = {0}; 939d5c65159SKalle Valo int ret; 940d5c65159SKalle Valo 941d5c65159SKalle Valo cmd.addr_lo = lower_32_bits(rx_tid->paddr); 942d5c65159SKalle Valo cmd.addr_hi = upper_32_bits(rx_tid->paddr); 943d5c65159SKalle Valo cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS; 944fe201947SVenkateswara Naralasetty cmd.upd0 = HAL_REO_CMD_UPD0_BA_WINDOW_SIZE; 945d5c65159SKalle Valo cmd.ba_window_size = ba_win_sz; 946fe201947SVenkateswara Naralasetty 947fe201947SVenkateswara Naralasetty if (update_ssn) { 948fe201947SVenkateswara Naralasetty cmd.upd0 |= HAL_REO_CMD_UPD0_SSN; 949d5c65159SKalle Valo cmd.upd2 = FIELD_PREP(HAL_REO_CMD_UPD2_SSN, ssn); 950fe201947SVenkateswara Naralasetty } 951d5c65159SKalle Valo 952d5c65159SKalle Valo ret = ath11k_dp_tx_send_reo_cmd(ar->ab, rx_tid, 953d5c65159SKalle Valo HAL_REO_CMD_UPDATE_RX_QUEUE, &cmd, 954d5c65159SKalle Valo NULL); 955d5c65159SKalle Valo if (ret) { 956d5c65159SKalle Valo ath11k_warn(ar->ab, "failed to update rx tid queue, tid %d (%d)\n", 957d5c65159SKalle Valo rx_tid->tid, ret); 958d5c65159SKalle Valo return ret; 959d5c65159SKalle Valo } 960d5c65159SKalle Valo 961d5c65159SKalle Valo rx_tid->ba_win_sz = ba_win_sz; 962d5c65159SKalle Valo 963d5c65159SKalle Valo return 0; 964d5c65159SKalle Valo } 965d5c65159SKalle Valo 966d5c65159SKalle Valo static void ath11k_dp_rx_tid_mem_free(struct ath11k_base *ab, 967d5c65159SKalle Valo const u8 *peer_mac, int vdev_id, u8 tid) 968d5c65159SKalle Valo { 969d5c65159SKalle Valo struct ath11k_peer *peer; 970d5c65159SKalle Valo struct dp_rx_tid *rx_tid; 971d5c65159SKalle Valo 972d5c65159SKalle Valo spin_lock_bh(&ab->base_lock); 973d5c65159SKalle Valo 974d5c65159SKalle Valo peer = ath11k_peer_find(ab, vdev_id, peer_mac); 975d5c65159SKalle Valo if (!peer) { 976d5c65159SKalle Valo ath11k_warn(ab, "failed to find the peer to free up rx tid mem\n"); 977d5c65159SKalle Valo goto unlock_exit; 978d5c65159SKalle Valo } 979d5c65159SKalle Valo 980d5c65159SKalle Valo rx_tid = &peer->rx_tid[tid]; 981d5c65159SKalle Valo if (!rx_tid->active) 982d5c65159SKalle Valo goto unlock_exit; 983d5c65159SKalle Valo 984d5c65159SKalle Valo dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size, 985d5c65159SKalle Valo DMA_BIDIRECTIONAL); 986d5c65159SKalle Valo kfree(rx_tid->vaddr); 98793a91f40SHarshitha Prem rx_tid->vaddr = NULL; 988d5c65159SKalle Valo 989d5c65159SKalle Valo rx_tid->active = false; 990d5c65159SKalle Valo 991d5c65159SKalle Valo unlock_exit: 992d5c65159SKalle Valo spin_unlock_bh(&ab->base_lock); 993d5c65159SKalle Valo } 994d5c65159SKalle Valo 995d5c65159SKalle Valo int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id, 9961441b2f2SManikanta Pubbisetty u8 tid, u32 ba_win_sz, u16 ssn, 9971441b2f2SManikanta Pubbisetty enum hal_pn_type pn_type) 998d5c65159SKalle Valo { 999d5c65159SKalle Valo struct ath11k_base *ab = ar->ab; 1000d5c65159SKalle Valo struct ath11k_peer *peer; 1001d5c65159SKalle Valo struct dp_rx_tid *rx_tid; 1002d5c65159SKalle Valo u32 hw_desc_sz; 1003d5c65159SKalle Valo u32 *addr_aligned; 1004d5c65159SKalle Valo void *vaddr; 1005d5c65159SKalle Valo dma_addr_t paddr; 1006d5c65159SKalle Valo int ret; 1007d5c65159SKalle Valo 1008d5c65159SKalle Valo spin_lock_bh(&ab->base_lock); 1009d5c65159SKalle Valo 1010d5c65159SKalle Valo peer = ath11k_peer_find(ab, vdev_id, peer_mac); 1011d5c65159SKalle Valo if (!peer) { 101220487cc3SHarshitha Prem ath11k_warn(ab, "failed to find the peer %pM to set up rx tid\n", 101320487cc3SHarshitha Prem peer_mac); 1014d5c65159SKalle Valo spin_unlock_bh(&ab->base_lock); 1015d5c65159SKalle Valo return -ENOENT; 1016d5c65159SKalle Valo } 1017d5c65159SKalle Valo 1018d5c65159SKalle Valo rx_tid = &peer->rx_tid[tid]; 1019d5c65159SKalle Valo /* Update the tid queue if it is already setup */ 1020d5c65159SKalle Valo if (rx_tid->active) { 1021d5c65159SKalle Valo paddr = rx_tid->paddr; 1022d5c65159SKalle Valo ret = ath11k_peer_rx_tid_reo_update(ar, peer, rx_tid, 1023fe201947SVenkateswara Naralasetty ba_win_sz, ssn, true); 1024d5c65159SKalle Valo spin_unlock_bh(&ab->base_lock); 1025d5c65159SKalle Valo if (ret) { 102620487cc3SHarshitha Prem ath11k_warn(ab, "failed to update reo for peer %pM rx tid %d\n: %d", 102720487cc3SHarshitha Prem peer_mac, tid, ret); 1028d5c65159SKalle Valo return ret; 1029d5c65159SKalle Valo } 1030d5c65159SKalle Valo 1031d5c65159SKalle Valo ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, 1032d5c65159SKalle Valo peer_mac, paddr, 1033d5c65159SKalle Valo tid, 1, ba_win_sz); 1034d5c65159SKalle Valo if (ret) 103520487cc3SHarshitha Prem ath11k_warn(ab, "failed to send wmi rx reorder queue for peer %pM tid %d: %d\n", 103620487cc3SHarshitha Prem peer_mac, tid, ret); 1037d5c65159SKalle Valo return ret; 1038d5c65159SKalle Valo } 1039d5c65159SKalle Valo 1040d5c65159SKalle Valo rx_tid->tid = tid; 1041d5c65159SKalle Valo 1042d5c65159SKalle Valo rx_tid->ba_win_sz = ba_win_sz; 1043d5c65159SKalle Valo 104416f283f0SKalle Valo /* TODO: Optimize the memory allocation for qos tid based on 1045d5c65159SKalle Valo * the actual BA window size in REO tid update path. 1046d5c65159SKalle Valo */ 1047d5c65159SKalle Valo if (tid == HAL_DESC_REO_NON_QOS_TID) 1048d5c65159SKalle Valo hw_desc_sz = ath11k_hal_reo_qdesc_size(ba_win_sz, tid); 1049d5c65159SKalle Valo else 1050d5c65159SKalle Valo hw_desc_sz = ath11k_hal_reo_qdesc_size(DP_BA_WIN_SZ_MAX, tid); 1051d5c65159SKalle Valo 105269c93f96SWei Yongjun vaddr = kzalloc(hw_desc_sz + HAL_LINK_DESC_ALIGN - 1, GFP_ATOMIC); 1053d5c65159SKalle Valo if (!vaddr) { 1054d5c65159SKalle Valo spin_unlock_bh(&ab->base_lock); 1055d5c65159SKalle Valo return -ENOMEM; 1056d5c65159SKalle Valo } 1057d5c65159SKalle Valo 1058d5c65159SKalle Valo addr_aligned = PTR_ALIGN(vaddr, HAL_LINK_DESC_ALIGN); 1059d5c65159SKalle Valo 10601441b2f2SManikanta Pubbisetty ath11k_hal_reo_qdesc_setup(addr_aligned, tid, ba_win_sz, 10611441b2f2SManikanta Pubbisetty ssn, pn_type); 1062d5c65159SKalle Valo 1063d5c65159SKalle Valo paddr = dma_map_single(ab->dev, addr_aligned, hw_desc_sz, 1064d5c65159SKalle Valo DMA_BIDIRECTIONAL); 1065d5c65159SKalle Valo 1066d5c65159SKalle Valo ret = dma_mapping_error(ab->dev, paddr); 1067d5c65159SKalle Valo if (ret) { 1068d5c65159SKalle Valo spin_unlock_bh(&ab->base_lock); 106920487cc3SHarshitha Prem ath11k_warn(ab, "failed to setup dma map for peer %pM rx tid %d: %d\n", 107020487cc3SHarshitha Prem peer_mac, tid, ret); 1071d5c65159SKalle Valo goto err_mem_free; 1072d5c65159SKalle Valo } 1073d5c65159SKalle Valo 1074d5c65159SKalle Valo rx_tid->vaddr = vaddr; 1075d5c65159SKalle Valo rx_tid->paddr = paddr; 1076d5c65159SKalle Valo rx_tid->size = hw_desc_sz; 1077d5c65159SKalle Valo rx_tid->active = true; 1078d5c65159SKalle Valo 1079d5c65159SKalle Valo spin_unlock_bh(&ab->base_lock); 1080d5c65159SKalle Valo 1081d5c65159SKalle Valo ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, peer_mac, 1082d5c65159SKalle Valo paddr, tid, 1, ba_win_sz); 1083d5c65159SKalle Valo if (ret) { 108420487cc3SHarshitha Prem ath11k_warn(ar->ab, "failed to setup rx reorder queue for peer %pM tid %d: %d\n", 108520487cc3SHarshitha Prem peer_mac, tid, ret); 1086d5c65159SKalle Valo ath11k_dp_rx_tid_mem_free(ab, peer_mac, vdev_id, tid); 1087d5c65159SKalle Valo } 1088d5c65159SKalle Valo 1089d5c65159SKalle Valo return ret; 1090d5c65159SKalle Valo 1091d5c65159SKalle Valo err_mem_free: 109293a91f40SHarshitha Prem kfree(rx_tid->vaddr); 109393a91f40SHarshitha Prem rx_tid->vaddr = NULL; 1094d5c65159SKalle Valo 1095d5c65159SKalle Valo return ret; 1096d5c65159SKalle Valo } 1097d5c65159SKalle Valo 1098d5c65159SKalle Valo int ath11k_dp_rx_ampdu_start(struct ath11k *ar, 1099d5c65159SKalle Valo struct ieee80211_ampdu_params *params) 1100d5c65159SKalle Valo { 1101d5c65159SKalle Valo struct ath11k_base *ab = ar->ab; 1102d5c65159SKalle Valo struct ath11k_sta *arsta = (void *)params->sta->drv_priv; 1103d5c65159SKalle Valo int vdev_id = arsta->arvif->vdev_id; 1104d5c65159SKalle Valo int ret; 1105d5c65159SKalle Valo 1106d5c65159SKalle Valo ret = ath11k_peer_rx_tid_setup(ar, params->sta->addr, vdev_id, 1107d5c65159SKalle Valo params->tid, params->buf_size, 11081441b2f2SManikanta Pubbisetty params->ssn, arsta->pn_type); 1109d5c65159SKalle Valo if (ret) 1110d5c65159SKalle Valo ath11k_warn(ab, "failed to setup rx tid %d\n", ret); 1111d5c65159SKalle Valo 1112d5c65159SKalle Valo return ret; 1113d5c65159SKalle Valo } 1114d5c65159SKalle Valo 1115d5c65159SKalle Valo int ath11k_dp_rx_ampdu_stop(struct ath11k *ar, 1116d5c65159SKalle Valo struct ieee80211_ampdu_params *params) 1117d5c65159SKalle Valo { 1118d5c65159SKalle Valo struct ath11k_base *ab = ar->ab; 1119d5c65159SKalle Valo struct ath11k_peer *peer; 1120d5c65159SKalle Valo struct ath11k_sta *arsta = (void *)params->sta->drv_priv; 1121d5c65159SKalle Valo int vdev_id = arsta->arvif->vdev_id; 1122d5c65159SKalle Valo dma_addr_t paddr; 1123d5c65159SKalle Valo bool active; 1124d5c65159SKalle Valo int ret; 1125d5c65159SKalle Valo 1126d5c65159SKalle Valo spin_lock_bh(&ab->base_lock); 1127d5c65159SKalle Valo 1128d5c65159SKalle Valo peer = ath11k_peer_find(ab, vdev_id, params->sta->addr); 1129d5c65159SKalle Valo if (!peer) { 1130d5c65159SKalle Valo ath11k_warn(ab, "failed to find the peer to stop rx aggregation\n"); 1131d5c65159SKalle Valo spin_unlock_bh(&ab->base_lock); 1132d5c65159SKalle Valo return -ENOENT; 1133d5c65159SKalle Valo } 1134d5c65159SKalle Valo 1135d5c65159SKalle Valo paddr = peer->rx_tid[params->tid].paddr; 1136d5c65159SKalle Valo active = peer->rx_tid[params->tid].active; 1137d5c65159SKalle Valo 1138fe201947SVenkateswara Naralasetty if (!active) { 1139d5c65159SKalle Valo spin_unlock_bh(&ab->base_lock); 1140d5c65159SKalle Valo return 0; 1141fe201947SVenkateswara Naralasetty } 1142fe201947SVenkateswara Naralasetty 1143fe201947SVenkateswara Naralasetty ret = ath11k_peer_rx_tid_reo_update(ar, peer, peer->rx_tid, 1, 0, false); 1144fe201947SVenkateswara Naralasetty spin_unlock_bh(&ab->base_lock); 1145fe201947SVenkateswara Naralasetty if (ret) { 1146fe201947SVenkateswara Naralasetty ath11k_warn(ab, "failed to update reo for rx tid %d: %d\n", 1147fe201947SVenkateswara Naralasetty params->tid, ret); 1148fe201947SVenkateswara Naralasetty return ret; 1149fe201947SVenkateswara Naralasetty } 1150d5c65159SKalle Valo 1151d5c65159SKalle Valo ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, 1152d5c65159SKalle Valo params->sta->addr, paddr, 1153d5c65159SKalle Valo params->tid, 1, 1); 1154d5c65159SKalle Valo if (ret) 1155d5c65159SKalle Valo ath11k_warn(ab, "failed to send wmi to delete rx tid %d\n", 1156d5c65159SKalle Valo ret); 1157d5c65159SKalle Valo 1158d5c65159SKalle Valo return ret; 1159d5c65159SKalle Valo } 1160d5c65159SKalle Valo 11611441b2f2SManikanta Pubbisetty int ath11k_dp_peer_rx_pn_replay_config(struct ath11k_vif *arvif, 11621441b2f2SManikanta Pubbisetty const u8 *peer_addr, 11631441b2f2SManikanta Pubbisetty enum set_key_cmd key_cmd, 11641441b2f2SManikanta Pubbisetty struct ieee80211_key_conf *key) 11651441b2f2SManikanta Pubbisetty { 11661441b2f2SManikanta Pubbisetty struct ath11k *ar = arvif->ar; 11671441b2f2SManikanta Pubbisetty struct ath11k_base *ab = ar->ab; 11681441b2f2SManikanta Pubbisetty struct ath11k_hal_reo_cmd cmd = {0}; 11691441b2f2SManikanta Pubbisetty struct ath11k_peer *peer; 11701441b2f2SManikanta Pubbisetty struct dp_rx_tid *rx_tid; 11711441b2f2SManikanta Pubbisetty u8 tid; 11721441b2f2SManikanta Pubbisetty int ret = 0; 11731441b2f2SManikanta Pubbisetty 11741441b2f2SManikanta Pubbisetty /* NOTE: Enable PN/TSC replay check offload only for unicast frames. 11751441b2f2SManikanta Pubbisetty * We use mac80211 PN/TSC replay check functionality for bcast/mcast 11761441b2f2SManikanta Pubbisetty * for now. 11771441b2f2SManikanta Pubbisetty */ 11781441b2f2SManikanta Pubbisetty if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 11791441b2f2SManikanta Pubbisetty return 0; 11801441b2f2SManikanta Pubbisetty 11811441b2f2SManikanta Pubbisetty cmd.flag |= HAL_REO_CMD_FLG_NEED_STATUS; 11821441b2f2SManikanta Pubbisetty cmd.upd0 |= HAL_REO_CMD_UPD0_PN | 11831441b2f2SManikanta Pubbisetty HAL_REO_CMD_UPD0_PN_SIZE | 11841441b2f2SManikanta Pubbisetty HAL_REO_CMD_UPD0_PN_VALID | 11851441b2f2SManikanta Pubbisetty HAL_REO_CMD_UPD0_PN_CHECK | 11861441b2f2SManikanta Pubbisetty HAL_REO_CMD_UPD0_SVLD; 11871441b2f2SManikanta Pubbisetty 11881441b2f2SManikanta Pubbisetty switch (key->cipher) { 11891441b2f2SManikanta Pubbisetty case WLAN_CIPHER_SUITE_TKIP: 11901441b2f2SManikanta Pubbisetty case WLAN_CIPHER_SUITE_CCMP: 11911441b2f2SManikanta Pubbisetty case WLAN_CIPHER_SUITE_CCMP_256: 11921441b2f2SManikanta Pubbisetty case WLAN_CIPHER_SUITE_GCMP: 11931441b2f2SManikanta Pubbisetty case WLAN_CIPHER_SUITE_GCMP_256: 11941441b2f2SManikanta Pubbisetty if (key_cmd == SET_KEY) { 11951441b2f2SManikanta Pubbisetty cmd.upd1 |= HAL_REO_CMD_UPD1_PN_CHECK; 11961441b2f2SManikanta Pubbisetty cmd.pn_size = 48; 11971441b2f2SManikanta Pubbisetty } 11981441b2f2SManikanta Pubbisetty break; 11991441b2f2SManikanta Pubbisetty default: 12001441b2f2SManikanta Pubbisetty break; 12011441b2f2SManikanta Pubbisetty } 12021441b2f2SManikanta Pubbisetty 12031441b2f2SManikanta Pubbisetty spin_lock_bh(&ab->base_lock); 12041441b2f2SManikanta Pubbisetty 12051441b2f2SManikanta Pubbisetty peer = ath11k_peer_find(ab, arvif->vdev_id, peer_addr); 12061441b2f2SManikanta Pubbisetty if (!peer) { 12071441b2f2SManikanta Pubbisetty ath11k_warn(ab, "failed to find the peer to configure pn replay detection\n"); 12081441b2f2SManikanta Pubbisetty spin_unlock_bh(&ab->base_lock); 12091441b2f2SManikanta Pubbisetty return -ENOENT; 12101441b2f2SManikanta Pubbisetty } 12111441b2f2SManikanta Pubbisetty 12121441b2f2SManikanta Pubbisetty for (tid = 0; tid <= IEEE80211_NUM_TIDS; tid++) { 12131441b2f2SManikanta Pubbisetty rx_tid = &peer->rx_tid[tid]; 12141441b2f2SManikanta Pubbisetty if (!rx_tid->active) 12151441b2f2SManikanta Pubbisetty continue; 12161441b2f2SManikanta Pubbisetty cmd.addr_lo = lower_32_bits(rx_tid->paddr); 12171441b2f2SManikanta Pubbisetty cmd.addr_hi = upper_32_bits(rx_tid->paddr); 12181441b2f2SManikanta Pubbisetty ret = ath11k_dp_tx_send_reo_cmd(ab, rx_tid, 12191441b2f2SManikanta Pubbisetty HAL_REO_CMD_UPDATE_RX_QUEUE, 12201441b2f2SManikanta Pubbisetty &cmd, NULL); 12211441b2f2SManikanta Pubbisetty if (ret) { 12221441b2f2SManikanta Pubbisetty ath11k_warn(ab, "failed to configure rx tid %d queue for pn replay detection %d\n", 12231441b2f2SManikanta Pubbisetty tid, ret); 12241441b2f2SManikanta Pubbisetty break; 12251441b2f2SManikanta Pubbisetty } 12261441b2f2SManikanta Pubbisetty } 12271441b2f2SManikanta Pubbisetty 1228abdcd4cbSDan Carpenter spin_unlock_bh(&ab->base_lock); 12291441b2f2SManikanta Pubbisetty 12301441b2f2SManikanta Pubbisetty return ret; 12311441b2f2SManikanta Pubbisetty } 12321441b2f2SManikanta Pubbisetty 12331441b2f2SManikanta Pubbisetty static inline int ath11k_get_ppdu_user_index(struct htt_ppdu_stats *ppdu_stats, 1234d5c65159SKalle Valo u16 peer_id) 1235d5c65159SKalle Valo { 1236d5c65159SKalle Valo int i; 1237d5c65159SKalle Valo 1238d5c65159SKalle Valo for (i = 0; i < HTT_PPDU_STATS_MAX_USERS - 1; i++) { 1239d5c65159SKalle Valo if (ppdu_stats->user_stats[i].is_valid_peer_id) { 1240d5c65159SKalle Valo if (peer_id == ppdu_stats->user_stats[i].peer_id) 1241d5c65159SKalle Valo return i; 1242d5c65159SKalle Valo } else { 1243d5c65159SKalle Valo return i; 1244d5c65159SKalle Valo } 1245d5c65159SKalle Valo } 1246d5c65159SKalle Valo 1247d5c65159SKalle Valo return -EINVAL; 1248d5c65159SKalle Valo } 1249d5c65159SKalle Valo 1250d5c65159SKalle Valo static int ath11k_htt_tlv_ppdu_stats_parse(struct ath11k_base *ab, 1251d5c65159SKalle Valo u16 tag, u16 len, const void *ptr, 1252d5c65159SKalle Valo void *data) 1253d5c65159SKalle Valo { 1254d5c65159SKalle Valo struct htt_ppdu_stats_info *ppdu_info; 1255d5c65159SKalle Valo struct htt_ppdu_user_stats *user_stats; 1256d5c65159SKalle Valo int cur_user; 1257d5c65159SKalle Valo u16 peer_id; 1258d5c65159SKalle Valo 1259d5c65159SKalle Valo ppdu_info = (struct htt_ppdu_stats_info *)data; 1260d5c65159SKalle Valo 1261d5c65159SKalle Valo switch (tag) { 1262d5c65159SKalle Valo case HTT_PPDU_STATS_TAG_COMMON: 1263d5c65159SKalle Valo if (len < sizeof(struct htt_ppdu_stats_common)) { 1264d5c65159SKalle Valo ath11k_warn(ab, "Invalid len %d for the tag 0x%x\n", 1265d5c65159SKalle Valo len, tag); 1266d5c65159SKalle Valo return -EINVAL; 1267d5c65159SKalle Valo } 1268d5c65159SKalle Valo memcpy((void *)&ppdu_info->ppdu_stats.common, ptr, 1269d5c65159SKalle Valo sizeof(struct htt_ppdu_stats_common)); 1270d5c65159SKalle Valo break; 1271d5c65159SKalle Valo case HTT_PPDU_STATS_TAG_USR_RATE: 1272d5c65159SKalle Valo if (len < sizeof(struct htt_ppdu_stats_user_rate)) { 1273d5c65159SKalle Valo ath11k_warn(ab, "Invalid len %d for the tag 0x%x\n", 1274d5c65159SKalle Valo len, tag); 1275d5c65159SKalle Valo return -EINVAL; 1276d5c65159SKalle Valo } 1277d5c65159SKalle Valo 1278d5c65159SKalle Valo peer_id = ((struct htt_ppdu_stats_user_rate *)ptr)->sw_peer_id; 1279d5c65159SKalle Valo cur_user = ath11k_get_ppdu_user_index(&ppdu_info->ppdu_stats, 1280d5c65159SKalle Valo peer_id); 1281d5c65159SKalle Valo if (cur_user < 0) 1282d5c65159SKalle Valo return -EINVAL; 1283d5c65159SKalle Valo user_stats = &ppdu_info->ppdu_stats.user_stats[cur_user]; 1284d5c65159SKalle Valo user_stats->peer_id = peer_id; 1285d5c65159SKalle Valo user_stats->is_valid_peer_id = true; 1286d5c65159SKalle Valo memcpy((void *)&user_stats->rate, ptr, 1287d5c65159SKalle Valo sizeof(struct htt_ppdu_stats_user_rate)); 1288d5c65159SKalle Valo user_stats->tlv_flags |= BIT(tag); 1289d5c65159SKalle Valo break; 1290d5c65159SKalle Valo case HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON: 1291d5c65159SKalle Valo if (len < sizeof(struct htt_ppdu_stats_usr_cmpltn_cmn)) { 1292d5c65159SKalle Valo ath11k_warn(ab, "Invalid len %d for the tag 0x%x\n", 1293d5c65159SKalle Valo len, tag); 1294d5c65159SKalle Valo return -EINVAL; 1295d5c65159SKalle Valo } 1296d5c65159SKalle Valo 1297d5c65159SKalle Valo peer_id = ((struct htt_ppdu_stats_usr_cmpltn_cmn *)ptr)->sw_peer_id; 1298d5c65159SKalle Valo cur_user = ath11k_get_ppdu_user_index(&ppdu_info->ppdu_stats, 1299d5c65159SKalle Valo peer_id); 1300d5c65159SKalle Valo if (cur_user < 0) 1301d5c65159SKalle Valo return -EINVAL; 1302d5c65159SKalle Valo user_stats = &ppdu_info->ppdu_stats.user_stats[cur_user]; 1303d5c65159SKalle Valo user_stats->peer_id = peer_id; 1304d5c65159SKalle Valo user_stats->is_valid_peer_id = true; 1305d5c65159SKalle Valo memcpy((void *)&user_stats->cmpltn_cmn, ptr, 1306d5c65159SKalle Valo sizeof(struct htt_ppdu_stats_usr_cmpltn_cmn)); 1307d5c65159SKalle Valo user_stats->tlv_flags |= BIT(tag); 1308d5c65159SKalle Valo break; 1309d5c65159SKalle Valo case HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS: 1310d5c65159SKalle Valo if (len < 1311d5c65159SKalle Valo sizeof(struct htt_ppdu_stats_usr_cmpltn_ack_ba_status)) { 1312d5c65159SKalle Valo ath11k_warn(ab, "Invalid len %d for the tag 0x%x\n", 1313d5c65159SKalle Valo len, tag); 1314d5c65159SKalle Valo return -EINVAL; 1315d5c65159SKalle Valo } 1316d5c65159SKalle Valo 1317d5c65159SKalle Valo peer_id = 1318d5c65159SKalle Valo ((struct htt_ppdu_stats_usr_cmpltn_ack_ba_status *)ptr)->sw_peer_id; 1319d5c65159SKalle Valo cur_user = ath11k_get_ppdu_user_index(&ppdu_info->ppdu_stats, 1320d5c65159SKalle Valo peer_id); 1321d5c65159SKalle Valo if (cur_user < 0) 1322d5c65159SKalle Valo return -EINVAL; 1323d5c65159SKalle Valo user_stats = &ppdu_info->ppdu_stats.user_stats[cur_user]; 1324d5c65159SKalle Valo user_stats->peer_id = peer_id; 1325d5c65159SKalle Valo user_stats->is_valid_peer_id = true; 1326d5c65159SKalle Valo memcpy((void *)&user_stats->ack_ba, ptr, 1327d5c65159SKalle Valo sizeof(struct htt_ppdu_stats_usr_cmpltn_ack_ba_status)); 1328d5c65159SKalle Valo user_stats->tlv_flags |= BIT(tag); 1329d5c65159SKalle Valo break; 1330d5c65159SKalle Valo } 1331d5c65159SKalle Valo return 0; 1332d5c65159SKalle Valo } 1333d5c65159SKalle Valo 1334d5c65159SKalle Valo int ath11k_dp_htt_tlv_iter(struct ath11k_base *ab, const void *ptr, size_t len, 1335d5c65159SKalle Valo int (*iter)(struct ath11k_base *ar, u16 tag, u16 len, 1336d5c65159SKalle Valo const void *ptr, void *data), 1337d5c65159SKalle Valo void *data) 1338d5c65159SKalle Valo { 1339d5c65159SKalle Valo const struct htt_tlv *tlv; 1340d5c65159SKalle Valo const void *begin = ptr; 1341d5c65159SKalle Valo u16 tlv_tag, tlv_len; 1342d5c65159SKalle Valo int ret = -EINVAL; 1343d5c65159SKalle Valo 1344d5c65159SKalle Valo while (len > 0) { 1345d5c65159SKalle Valo if (len < sizeof(*tlv)) { 1346d5c65159SKalle Valo ath11k_err(ab, "htt tlv parse failure at byte %zd (%zu bytes left, %zu expected)\n", 1347d5c65159SKalle Valo ptr - begin, len, sizeof(*tlv)); 1348d5c65159SKalle Valo return -EINVAL; 1349d5c65159SKalle Valo } 1350d5c65159SKalle Valo tlv = (struct htt_tlv *)ptr; 1351d5c65159SKalle Valo tlv_tag = FIELD_GET(HTT_TLV_TAG, tlv->header); 1352d5c65159SKalle Valo tlv_len = FIELD_GET(HTT_TLV_LEN, tlv->header); 1353d5c65159SKalle Valo ptr += sizeof(*tlv); 1354d5c65159SKalle Valo len -= sizeof(*tlv); 1355d5c65159SKalle Valo 1356d5c65159SKalle Valo if (tlv_len > len) { 1357bb2d2dfdSTom Rix ath11k_err(ab, "htt tlv parse failure of tag %u at byte %zd (%zu bytes left, %u expected)\n", 1358d5c65159SKalle Valo tlv_tag, ptr - begin, len, tlv_len); 1359d5c65159SKalle Valo return -EINVAL; 1360d5c65159SKalle Valo } 1361d5c65159SKalle Valo ret = iter(ab, tlv_tag, tlv_len, ptr, data); 1362d5c65159SKalle Valo if (ret == -ENOMEM) 1363d5c65159SKalle Valo return ret; 1364d5c65159SKalle Valo 1365d5c65159SKalle Valo ptr += tlv_len; 1366d5c65159SKalle Valo len -= tlv_len; 1367d5c65159SKalle Valo } 1368d5c65159SKalle Valo return 0; 1369d5c65159SKalle Valo } 1370d5c65159SKalle Valo 1371d5c65159SKalle Valo static void 1372d5c65159SKalle Valo ath11k_update_per_peer_tx_stats(struct ath11k *ar, 1373d5c65159SKalle Valo struct htt_ppdu_stats *ppdu_stats, u8 user) 1374d5c65159SKalle Valo { 1375d5c65159SKalle Valo struct ath11k_base *ab = ar->ab; 1376d5c65159SKalle Valo struct ath11k_peer *peer; 1377d5c65159SKalle Valo struct ieee80211_sta *sta; 1378d5c65159SKalle Valo struct ath11k_sta *arsta; 1379d5c65159SKalle Valo struct htt_ppdu_stats_user_rate *user_rate; 1380d5c65159SKalle Valo struct ath11k_per_peer_tx_stats *peer_stats = &ar->peer_tx_stats; 1381d5c65159SKalle Valo struct htt_ppdu_user_stats *usr_stats = &ppdu_stats->user_stats[user]; 1382d5c65159SKalle Valo struct htt_ppdu_stats_common *common = &ppdu_stats->common; 1383d5c65159SKalle Valo int ret; 13846a0c3702SJohn Crispin u8 flags, mcs, nss, bw, sgi, dcm, rate_idx = 0; 1385d5c65159SKalle Valo u32 succ_bytes = 0; 1386d5c65159SKalle Valo u16 rate = 0, succ_pkts = 0; 1387d5c65159SKalle Valo u32 tx_duration = 0; 1388b9269a07SVenkateswara Naralasetty u8 tid = HTT_PPDU_STATS_NON_QOS_TID; 1389d5c65159SKalle Valo bool is_ampdu = false; 1390d5c65159SKalle Valo 1391d5c65159SKalle Valo if (!usr_stats) 1392d5c65159SKalle Valo return; 1393d5c65159SKalle Valo 1394d5c65159SKalle Valo if (!(usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_RATE))) 1395d5c65159SKalle Valo return; 1396d5c65159SKalle Valo 1397d5c65159SKalle Valo if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON)) 1398d5c65159SKalle Valo is_ampdu = 1399d5c65159SKalle Valo HTT_USR_CMPLTN_IS_AMPDU(usr_stats->cmpltn_cmn.flags); 1400d5c65159SKalle Valo 1401d5c65159SKalle Valo if (usr_stats->tlv_flags & 1402d5c65159SKalle Valo BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS)) { 1403d5c65159SKalle Valo succ_bytes = usr_stats->ack_ba.success_bytes; 1404d5c65159SKalle Valo succ_pkts = FIELD_GET(HTT_PPDU_STATS_ACK_BA_INFO_NUM_MSDU_M, 1405d5c65159SKalle Valo usr_stats->ack_ba.info); 1406b9269a07SVenkateswara Naralasetty tid = FIELD_GET(HTT_PPDU_STATS_ACK_BA_INFO_TID_NUM, 1407b9269a07SVenkateswara Naralasetty usr_stats->ack_ba.info); 1408d5c65159SKalle Valo } 1409d5c65159SKalle Valo 1410d5c65159SKalle Valo if (common->fes_duration_us) 1411d5c65159SKalle Valo tx_duration = common->fes_duration_us; 1412d5c65159SKalle Valo 1413d5c65159SKalle Valo user_rate = &usr_stats->rate; 1414d5c65159SKalle Valo flags = HTT_USR_RATE_PREAMBLE(user_rate->rate_flags); 1415d5c65159SKalle Valo bw = HTT_USR_RATE_BW(user_rate->rate_flags) - 2; 1416d5c65159SKalle Valo nss = HTT_USR_RATE_NSS(user_rate->rate_flags) + 1; 1417d5c65159SKalle Valo mcs = HTT_USR_RATE_MCS(user_rate->rate_flags); 1418d5c65159SKalle Valo sgi = HTT_USR_RATE_GI(user_rate->rate_flags); 14196a0c3702SJohn Crispin dcm = HTT_USR_RATE_DCM(user_rate->rate_flags); 1420d5c65159SKalle Valo 1421d5c65159SKalle Valo /* Note: If host configured fixed rates and in some other special 1422d5c65159SKalle Valo * cases, the broadcast/management frames are sent in different rates. 1423d5c65159SKalle Valo * Firmware rate's control to be skipped for this? 1424d5c65159SKalle Valo */ 1425d5c65159SKalle Valo 14266a0c3702SJohn Crispin if (flags == WMI_RATE_PREAMBLE_HE && mcs > ATH11K_HE_MCS_MAX) { 1427bb2d2dfdSTom Rix ath11k_warn(ab, "Invalid HE mcs %d peer stats", mcs); 14286a0c3702SJohn Crispin return; 14296a0c3702SJohn Crispin } 14306a0c3702SJohn Crispin 14316a0c3702SJohn Crispin if (flags == WMI_RATE_PREAMBLE_VHT && mcs > ATH11K_VHT_MCS_MAX) { 1432bb2d2dfdSTom Rix ath11k_warn(ab, "Invalid VHT mcs %d peer stats", mcs); 1433d5c65159SKalle Valo return; 1434d5c65159SKalle Valo } 1435d5c65159SKalle Valo 14366a0c3702SJohn Crispin if (flags == WMI_RATE_PREAMBLE_HT && (mcs > ATH11K_HT_MCS_MAX || nss < 1)) { 1437bb2d2dfdSTom Rix ath11k_warn(ab, "Invalid HT mcs %d nss %d peer stats", 1438d5c65159SKalle Valo mcs, nss); 1439d5c65159SKalle Valo return; 1440d5c65159SKalle Valo } 1441d5c65159SKalle Valo 1442d5c65159SKalle Valo if (flags == WMI_RATE_PREAMBLE_CCK || flags == WMI_RATE_PREAMBLE_OFDM) { 1443d5c65159SKalle Valo ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs, 1444d5c65159SKalle Valo flags, 1445d5c65159SKalle Valo &rate_idx, 1446d5c65159SKalle Valo &rate); 1447d5c65159SKalle Valo if (ret < 0) 1448d5c65159SKalle Valo return; 1449d5c65159SKalle Valo } 1450d5c65159SKalle Valo 1451d5c65159SKalle Valo rcu_read_lock(); 1452d5c65159SKalle Valo spin_lock_bh(&ab->base_lock); 1453d5c65159SKalle Valo peer = ath11k_peer_find_by_id(ab, usr_stats->peer_id); 1454d5c65159SKalle Valo 1455d5c65159SKalle Valo if (!peer || !peer->sta) { 1456d5c65159SKalle Valo spin_unlock_bh(&ab->base_lock); 1457d5c65159SKalle Valo rcu_read_unlock(); 1458d5c65159SKalle Valo return; 1459d5c65159SKalle Valo } 1460d5c65159SKalle Valo 1461d5c65159SKalle Valo sta = peer->sta; 1462d5c65159SKalle Valo arsta = (struct ath11k_sta *)sta->drv_priv; 1463d5c65159SKalle Valo 1464d5c65159SKalle Valo memset(&arsta->txrate, 0, sizeof(arsta->txrate)); 1465d5c65159SKalle Valo 1466d5c65159SKalle Valo switch (flags) { 1467d5c65159SKalle Valo case WMI_RATE_PREAMBLE_OFDM: 1468d5c65159SKalle Valo arsta->txrate.legacy = rate; 1469d5c65159SKalle Valo break; 1470d5c65159SKalle Valo case WMI_RATE_PREAMBLE_CCK: 1471d5c65159SKalle Valo arsta->txrate.legacy = rate; 1472d5c65159SKalle Valo break; 1473d5c65159SKalle Valo case WMI_RATE_PREAMBLE_HT: 1474d5c65159SKalle Valo arsta->txrate.mcs = mcs + 8 * (nss - 1); 1475d5c65159SKalle Valo arsta->txrate.flags = RATE_INFO_FLAGS_MCS; 1476be43ce64SJohn Crispin if (sgi) 1477d5c65159SKalle Valo arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; 1478d5c65159SKalle Valo break; 1479d5c65159SKalle Valo case WMI_RATE_PREAMBLE_VHT: 1480d5c65159SKalle Valo arsta->txrate.mcs = mcs; 1481d5c65159SKalle Valo arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS; 1482be43ce64SJohn Crispin if (sgi) 1483d5c65159SKalle Valo arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; 1484d5c65159SKalle Valo break; 14856a0c3702SJohn Crispin case WMI_RATE_PREAMBLE_HE: 14866a0c3702SJohn Crispin arsta->txrate.mcs = mcs; 14876a0c3702SJohn Crispin arsta->txrate.flags = RATE_INFO_FLAGS_HE_MCS; 14886a0c3702SJohn Crispin arsta->txrate.he_dcm = dcm; 14891b8bb94cSWen Gong arsta->txrate.he_gi = ath11k_mac_he_gi_to_nl80211_he_gi(sgi); 14901b8bb94cSWen Gong arsta->txrate.he_ru_alloc = ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc 14911b8bb94cSWen Gong ((user_rate->ru_end - 14926a0c3702SJohn Crispin user_rate->ru_start) + 1); 14936a0c3702SJohn Crispin break; 1494d5c65159SKalle Valo } 1495d5c65159SKalle Valo 1496d5c65159SKalle Valo arsta->txrate.nss = nss; 14971b8bb94cSWen Gong 149839e81c6aSTamizh chelvam arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw); 1499a9e945eaSVenkateswara Naralasetty arsta->tx_duration += tx_duration; 1500d5c65159SKalle Valo memcpy(&arsta->last_txrate, &arsta->txrate, sizeof(struct rate_info)); 1501d5c65159SKalle Valo 1502b9269a07SVenkateswara Naralasetty /* PPDU stats reported for mgmt packet doesn't have valid tx bytes. 1503b9269a07SVenkateswara Naralasetty * So skip peer stats update for mgmt packets. 1504b9269a07SVenkateswara Naralasetty */ 1505b9269a07SVenkateswara Naralasetty if (tid < HTT_PPDU_STATS_NON_QOS_TID) { 1506d5c65159SKalle Valo memset(peer_stats, 0, sizeof(*peer_stats)); 1507d5c65159SKalle Valo peer_stats->succ_pkts = succ_pkts; 1508d5c65159SKalle Valo peer_stats->succ_bytes = succ_bytes; 1509d5c65159SKalle Valo peer_stats->is_ampdu = is_ampdu; 1510d5c65159SKalle Valo peer_stats->duration = tx_duration; 1511d5c65159SKalle Valo peer_stats->ba_fails = 1512d5c65159SKalle Valo HTT_USR_CMPLTN_LONG_RETRY(usr_stats->cmpltn_cmn.flags) + 1513d5c65159SKalle Valo HTT_USR_CMPLTN_SHORT_RETRY(usr_stats->cmpltn_cmn.flags); 1514d5c65159SKalle Valo 1515cb4e57dbSKalle Valo if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) 1516568f0603SKalle Valo ath11k_debugfs_sta_add_tx_stats(arsta, peer_stats, rate_idx); 1517b9269a07SVenkateswara Naralasetty } 1518d5c65159SKalle Valo 1519d5c65159SKalle Valo spin_unlock_bh(&ab->base_lock); 1520d5c65159SKalle Valo rcu_read_unlock(); 1521d5c65159SKalle Valo } 1522d5c65159SKalle Valo 1523d5c65159SKalle Valo static void ath11k_htt_update_ppdu_stats(struct ath11k *ar, 1524d5c65159SKalle Valo struct htt_ppdu_stats *ppdu_stats) 1525d5c65159SKalle Valo { 1526d5c65159SKalle Valo u8 user; 1527d5c65159SKalle Valo 1528d5c65159SKalle Valo for (user = 0; user < HTT_PPDU_STATS_MAX_USERS - 1; user++) 1529d5c65159SKalle Valo ath11k_update_per_peer_tx_stats(ar, ppdu_stats, user); 1530d5c65159SKalle Valo } 1531d5c65159SKalle Valo 1532d5c65159SKalle Valo static 1533d5c65159SKalle Valo struct htt_ppdu_stats_info *ath11k_dp_htt_get_ppdu_desc(struct ath11k *ar, 1534d5c65159SKalle Valo u32 ppdu_id) 1535d5c65159SKalle Valo { 1536269663f1SDan Carpenter struct htt_ppdu_stats_info *ppdu_info; 1537d5c65159SKalle Valo 1538e44de904SGovindaraj Saminathan lockdep_assert_held(&ar->data_lock); 1539e44de904SGovindaraj Saminathan 1540d5c65159SKalle Valo if (!list_empty(&ar->ppdu_stats_info)) { 1541d5c65159SKalle Valo list_for_each_entry(ppdu_info, &ar->ppdu_stats_info, list) { 1542e44de904SGovindaraj Saminathan if (ppdu_info->ppdu_id == ppdu_id) 1543d5c65159SKalle Valo return ppdu_info; 1544d5c65159SKalle Valo } 1545d5c65159SKalle Valo 1546d5c65159SKalle Valo if (ar->ppdu_stat_list_depth > HTT_PPDU_DESC_MAX_DEPTH) { 1547d5c65159SKalle Valo ppdu_info = list_first_entry(&ar->ppdu_stats_info, 1548d5c65159SKalle Valo typeof(*ppdu_info), list); 1549d5c65159SKalle Valo list_del(&ppdu_info->list); 1550d5c65159SKalle Valo ar->ppdu_stat_list_depth--; 1551d5c65159SKalle Valo ath11k_htt_update_ppdu_stats(ar, &ppdu_info->ppdu_stats); 1552d5c65159SKalle Valo kfree(ppdu_info); 1553d5c65159SKalle Valo } 1554d5c65159SKalle Valo } 1555d5c65159SKalle Valo 15566a8be1baSWen Gong ppdu_info = kzalloc(sizeof(*ppdu_info), GFP_ATOMIC); 1557d5c65159SKalle Valo if (!ppdu_info) 1558d5c65159SKalle Valo return NULL; 1559d5c65159SKalle Valo 1560d5c65159SKalle Valo list_add_tail(&ppdu_info->list, &ar->ppdu_stats_info); 1561d5c65159SKalle Valo ar->ppdu_stat_list_depth++; 1562d5c65159SKalle Valo 1563d5c65159SKalle Valo return ppdu_info; 1564d5c65159SKalle Valo } 1565d5c65159SKalle Valo 1566d5c65159SKalle Valo static int ath11k_htt_pull_ppdu_stats(struct ath11k_base *ab, 1567d5c65159SKalle Valo struct sk_buff *skb) 1568d5c65159SKalle Valo { 1569d5c65159SKalle Valo struct ath11k_htt_ppdu_stats_msg *msg; 1570d5c65159SKalle Valo struct htt_ppdu_stats_info *ppdu_info; 1571d5c65159SKalle Valo struct ath11k *ar; 1572d5c65159SKalle Valo int ret; 1573d5c65159SKalle Valo u8 pdev_id; 1574d5c65159SKalle Valo u32 ppdu_id, len; 1575d5c65159SKalle Valo 1576d5c65159SKalle Valo msg = (struct ath11k_htt_ppdu_stats_msg *)skb->data; 1577d5c65159SKalle Valo len = FIELD_GET(HTT_T2H_PPDU_STATS_INFO_PAYLOAD_SIZE, msg->info); 1578d5c65159SKalle Valo pdev_id = FIELD_GET(HTT_T2H_PPDU_STATS_INFO_PDEV_ID, msg->info); 1579d5c65159SKalle Valo ppdu_id = msg->ppdu_id; 1580d5c65159SKalle Valo 1581d5c65159SKalle Valo rcu_read_lock(); 1582d5c65159SKalle Valo ar = ath11k_mac_get_ar_by_pdev_id(ab, pdev_id); 1583d5c65159SKalle Valo if (!ar) { 1584d5c65159SKalle Valo ret = -EINVAL; 1585e44de904SGovindaraj Saminathan goto out; 1586d5c65159SKalle Valo } 1587d5c65159SKalle Valo 1588cb4e57dbSKalle Valo if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar)) 1589d5c65159SKalle Valo trace_ath11k_htt_ppdu_stats(ar, skb->data, len); 1590d5c65159SKalle Valo 1591e44de904SGovindaraj Saminathan spin_lock_bh(&ar->data_lock); 1592d5c65159SKalle Valo ppdu_info = ath11k_dp_htt_get_ppdu_desc(ar, ppdu_id); 1593d5c65159SKalle Valo if (!ppdu_info) { 1594d5c65159SKalle Valo ret = -EINVAL; 1595e44de904SGovindaraj Saminathan goto out_unlock_data; 1596d5c65159SKalle Valo } 1597d5c65159SKalle Valo 1598d5c65159SKalle Valo ppdu_info->ppdu_id = ppdu_id; 1599d5c65159SKalle Valo ret = ath11k_dp_htt_tlv_iter(ab, msg->data, len, 1600d5c65159SKalle Valo ath11k_htt_tlv_ppdu_stats_parse, 1601d5c65159SKalle Valo (void *)ppdu_info); 1602d5c65159SKalle Valo if (ret) { 1603d5c65159SKalle Valo ath11k_warn(ab, "Failed to parse tlv %d\n", ret); 1604e44de904SGovindaraj Saminathan goto out_unlock_data; 1605d5c65159SKalle Valo } 1606d5c65159SKalle Valo 1607e44de904SGovindaraj Saminathan out_unlock_data: 1608e44de904SGovindaraj Saminathan spin_unlock_bh(&ar->data_lock); 1609e44de904SGovindaraj Saminathan 1610e44de904SGovindaraj Saminathan out: 1611d5c65159SKalle Valo rcu_read_unlock(); 1612d5c65159SKalle Valo 1613d5c65159SKalle Valo return ret; 1614d5c65159SKalle Valo } 1615d5c65159SKalle Valo 1616d5c65159SKalle Valo static void ath11k_htt_pktlog(struct ath11k_base *ab, struct sk_buff *skb) 1617d5c65159SKalle Valo { 1618d5c65159SKalle Valo struct htt_pktlog_msg *data = (struct htt_pktlog_msg *)skb->data; 1619443d2ee7SAnilkumar Kolli struct ath_pktlog_hdr *hdr = (struct ath_pktlog_hdr *)data; 1620d5c65159SKalle Valo struct ath11k *ar; 1621d5c65159SKalle Valo u8 pdev_id; 1622d5c65159SKalle Valo 1623d5c65159SKalle Valo pdev_id = FIELD_GET(HTT_T2H_PPDU_STATS_INFO_PDEV_ID, data->hdr); 1624d0f390eaSAnilkumar Kolli ar = ath11k_mac_get_ar_by_pdev_id(ab, pdev_id); 1625d0f390eaSAnilkumar Kolli if (!ar) { 1626d0f390eaSAnilkumar Kolli ath11k_warn(ab, "invalid pdev id %d on htt pktlog\n", pdev_id); 1627d0f390eaSAnilkumar Kolli return; 1628d0f390eaSAnilkumar Kolli } 1629d5c65159SKalle Valo 163021c1b063SMaharaja Kennadyrajan trace_ath11k_htt_pktlog(ar, data->payload, hdr->size, 163121c1b063SMaharaja Kennadyrajan ar->ab->pktlog_defs_checksum); 1632d5c65159SKalle Valo } 1633d5c65159SKalle Valo 1634678e8414SSriram R static void ath11k_htt_backpressure_event_handler(struct ath11k_base *ab, 1635678e8414SSriram R struct sk_buff *skb) 1636678e8414SSriram R { 1637678e8414SSriram R u32 *data = (u32 *)skb->data; 163871fbc847SSriram R u8 pdev_id, ring_type, ring_id, pdev_idx; 1639678e8414SSriram R u16 hp, tp; 1640678e8414SSriram R u32 backpressure_time; 164171fbc847SSriram R struct ath11k_bp_stats *bp_stats; 1642678e8414SSriram R 1643678e8414SSriram R pdev_id = FIELD_GET(HTT_BACKPRESSURE_EVENT_PDEV_ID_M, *data); 1644678e8414SSriram R ring_type = FIELD_GET(HTT_BACKPRESSURE_EVENT_RING_TYPE_M, *data); 1645678e8414SSriram R ring_id = FIELD_GET(HTT_BACKPRESSURE_EVENT_RING_ID_M, *data); 1646678e8414SSriram R ++data; 1647678e8414SSriram R 1648678e8414SSriram R hp = FIELD_GET(HTT_BACKPRESSURE_EVENT_HP_M, *data); 1649678e8414SSriram R tp = FIELD_GET(HTT_BACKPRESSURE_EVENT_TP_M, *data); 1650678e8414SSriram R ++data; 1651678e8414SSriram R 1652678e8414SSriram R backpressure_time = *data; 1653678e8414SSriram R 1654fc3b984aSKalle Valo ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "backpressure event, pdev %d, ring type %d,ring id %d, hp %d tp %d, backpressure time %d\n", 1655678e8414SSriram R pdev_id, ring_type, ring_id, hp, tp, backpressure_time); 165671fbc847SSriram R 165771fbc847SSriram R if (ring_type == HTT_BACKPRESSURE_UMAC_RING_TYPE) { 165871fbc847SSriram R if (ring_id >= HTT_SW_UMAC_RING_IDX_MAX) 165971fbc847SSriram R return; 166071fbc847SSriram R 166171fbc847SSriram R bp_stats = &ab->soc_stats.bp_stats.umac_ring_bp_stats[ring_id]; 166271fbc847SSriram R } else if (ring_type == HTT_BACKPRESSURE_LMAC_RING_TYPE) { 166371fbc847SSriram R pdev_idx = DP_HW2SW_MACID(pdev_id); 166471fbc847SSriram R 166571fbc847SSriram R if (ring_id >= HTT_SW_LMAC_RING_IDX_MAX || pdev_idx >= MAX_RADIOS) 166671fbc847SSriram R return; 166771fbc847SSriram R 166871fbc847SSriram R bp_stats = &ab->soc_stats.bp_stats.lmac_ring_bp_stats[ring_id][pdev_idx]; 166971fbc847SSriram R } else { 167071fbc847SSriram R ath11k_warn(ab, "unknown ring type received in htt bp event %d\n", 167171fbc847SSriram R ring_type); 167271fbc847SSriram R return; 167371fbc847SSriram R } 167471fbc847SSriram R 167571fbc847SSriram R spin_lock_bh(&ab->base_lock); 167671fbc847SSriram R bp_stats->hp = hp; 167771fbc847SSriram R bp_stats->tp = tp; 167871fbc847SSriram R bp_stats->count++; 167971fbc847SSriram R bp_stats->jiffies = jiffies; 168071fbc847SSriram R spin_unlock_bh(&ab->base_lock); 1681678e8414SSriram R } 1682678e8414SSriram R 1683d5c65159SKalle Valo void ath11k_dp_htt_htc_t2h_msg_handler(struct ath11k_base *ab, 1684d5c65159SKalle Valo struct sk_buff *skb) 1685d5c65159SKalle Valo { 1686d5c65159SKalle Valo struct ath11k_dp *dp = &ab->dp; 1687d5c65159SKalle Valo struct htt_resp_msg *resp = (struct htt_resp_msg *)skb->data; 1688d5c65159SKalle Valo enum htt_t2h_msg_type type = FIELD_GET(HTT_T2H_MSG_TYPE, *(u32 *)resp); 1689d5c65159SKalle Valo u16 peer_id; 1690d5c65159SKalle Valo u8 vdev_id; 1691d5c65159SKalle Valo u8 mac_addr[ETH_ALEN]; 1692d5c65159SKalle Valo u16 peer_mac_h16; 1693d5c65159SKalle Valo u16 ast_hash; 16944b965be5SKarthikeyan Periyasamy u16 hw_peer_id; 1695d5c65159SKalle Valo 1696d5c65159SKalle Valo ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "dp_htt rx msg type :0x%0x\n", type); 1697d5c65159SKalle Valo 1698d5c65159SKalle Valo switch (type) { 1699d5c65159SKalle Valo case HTT_T2H_MSG_TYPE_VERSION_CONF: 1700d5c65159SKalle Valo dp->htt_tgt_ver_major = FIELD_GET(HTT_T2H_VERSION_CONF_MAJOR, 1701d5c65159SKalle Valo resp->version_msg.version); 1702d5c65159SKalle Valo dp->htt_tgt_ver_minor = FIELD_GET(HTT_T2H_VERSION_CONF_MINOR, 1703d5c65159SKalle Valo resp->version_msg.version); 1704d5c65159SKalle Valo complete(&dp->htt_tgt_version_received); 1705d5c65159SKalle Valo break; 1706d5c65159SKalle Valo case HTT_T2H_MSG_TYPE_PEER_MAP: 1707a6275302SCarl Huang vdev_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_VDEV_ID, 1708a6275302SCarl Huang resp->peer_map_ev.info); 1709a6275302SCarl Huang peer_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_PEER_ID, 1710a6275302SCarl Huang resp->peer_map_ev.info); 1711a6275302SCarl Huang peer_mac_h16 = FIELD_GET(HTT_T2H_PEER_MAP_INFO1_MAC_ADDR_H16, 1712a6275302SCarl Huang resp->peer_map_ev.info1); 1713a6275302SCarl Huang ath11k_dp_get_mac_addr(resp->peer_map_ev.mac_addr_l32, 1714a6275302SCarl Huang peer_mac_h16, mac_addr); 17154b965be5SKarthikeyan Periyasamy ath11k_peer_map_event(ab, vdev_id, peer_id, mac_addr, 0, 0); 1716a6275302SCarl Huang break; 171713ecd81fSCarl Huang case HTT_T2H_MSG_TYPE_PEER_MAP2: 1718d5c65159SKalle Valo vdev_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_VDEV_ID, 1719d5c65159SKalle Valo resp->peer_map_ev.info); 1720d5c65159SKalle Valo peer_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_PEER_ID, 1721d5c65159SKalle Valo resp->peer_map_ev.info); 1722d5c65159SKalle Valo peer_mac_h16 = FIELD_GET(HTT_T2H_PEER_MAP_INFO1_MAC_ADDR_H16, 1723d5c65159SKalle Valo resp->peer_map_ev.info1); 1724d5c65159SKalle Valo ath11k_dp_get_mac_addr(resp->peer_map_ev.mac_addr_l32, 1725d5c65159SKalle Valo peer_mac_h16, mac_addr); 1726d5c65159SKalle Valo ast_hash = FIELD_GET(HTT_T2H_PEER_MAP_INFO2_AST_HASH_VAL, 17270f37fbf4SAnilkumar Kolli resp->peer_map_ev.info2); 17284b965be5SKarthikeyan Periyasamy hw_peer_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO1_HW_PEER_ID, 17294b965be5SKarthikeyan Periyasamy resp->peer_map_ev.info1); 17304b965be5SKarthikeyan Periyasamy ath11k_peer_map_event(ab, vdev_id, peer_id, mac_addr, ast_hash, 17314b965be5SKarthikeyan Periyasamy hw_peer_id); 1732d5c65159SKalle Valo break; 1733d5c65159SKalle Valo case HTT_T2H_MSG_TYPE_PEER_UNMAP: 173413ecd81fSCarl Huang case HTT_T2H_MSG_TYPE_PEER_UNMAP2: 1735d5c65159SKalle Valo peer_id = FIELD_GET(HTT_T2H_PEER_UNMAP_INFO_PEER_ID, 1736d5c65159SKalle Valo resp->peer_unmap_ev.info); 1737d5c65159SKalle Valo ath11k_peer_unmap_event(ab, peer_id); 1738d5c65159SKalle Valo break; 1739d5c65159SKalle Valo case HTT_T2H_MSG_TYPE_PPDU_STATS_IND: 1740d5c65159SKalle Valo ath11k_htt_pull_ppdu_stats(ab, skb); 1741d5c65159SKalle Valo break; 1742d5c65159SKalle Valo case HTT_T2H_MSG_TYPE_EXT_STATS_CONF: 1743568f0603SKalle Valo ath11k_debugfs_htt_ext_stats_handler(ab, skb); 1744d5c65159SKalle Valo break; 1745d5c65159SKalle Valo case HTT_T2H_MSG_TYPE_PKTLOG: 1746d5c65159SKalle Valo ath11k_htt_pktlog(ab, skb); 1747d5c65159SKalle Valo break; 1748678e8414SSriram R case HTT_T2H_MSG_TYPE_BKPRESSURE_EVENT_IND: 1749678e8414SSriram R ath11k_htt_backpressure_event_handler(ab, skb); 1750678e8414SSriram R break; 1751d5c65159SKalle Valo default: 1752d5c65159SKalle Valo ath11k_warn(ab, "htt event %d not handled\n", type); 1753d5c65159SKalle Valo break; 1754d5c65159SKalle Valo } 1755d5c65159SKalle Valo 1756d5c65159SKalle Valo dev_kfree_skb_any(skb); 1757d5c65159SKalle Valo } 1758d5c65159SKalle Valo 1759d5c65159SKalle Valo static int ath11k_dp_rx_msdu_coalesce(struct ath11k *ar, 1760d5c65159SKalle Valo struct sk_buff_head *msdu_list, 1761d5c65159SKalle Valo struct sk_buff *first, struct sk_buff *last, 1762d5c65159SKalle Valo u8 l3pad_bytes, int msdu_len) 1763d5c65159SKalle Valo { 1764e678fbd4SKarthikeyan Periyasamy struct ath11k_base *ab = ar->ab; 1765d5c65159SKalle Valo struct sk_buff *skb; 1766d5c65159SKalle Valo struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(first); 1767d2f510faSSriram R int buf_first_hdr_len, buf_first_len; 1768d5c65159SKalle Valo struct hal_rx_desc *ldesc; 1769e678fbd4SKarthikeyan Periyasamy int space_extra, rem_len, buf_len; 1770e678fbd4SKarthikeyan Periyasamy u32 hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz; 1771d5c65159SKalle Valo 1772d2f510faSSriram R /* As the msdu is spread across multiple rx buffers, 1773d2f510faSSriram R * find the offset to the start of msdu for computing 1774d2f510faSSriram R * the length of the msdu in the first buffer. 1775d2f510faSSriram R */ 1776e678fbd4SKarthikeyan Periyasamy buf_first_hdr_len = hal_rx_desc_sz + l3pad_bytes; 1777d2f510faSSriram R buf_first_len = DP_RX_BUFFER_SIZE - buf_first_hdr_len; 1778d2f510faSSriram R 1779d2f510faSSriram R if (WARN_ON_ONCE(msdu_len <= buf_first_len)) { 1780d2f510faSSriram R skb_put(first, buf_first_hdr_len + msdu_len); 1781d2f510faSSriram R skb_pull(first, buf_first_hdr_len); 1782d5c65159SKalle Valo return 0; 1783d5c65159SKalle Valo } 1784d5c65159SKalle Valo 1785d5c65159SKalle Valo ldesc = (struct hal_rx_desc *)last->data; 1786e678fbd4SKarthikeyan Periyasamy rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(ab, ldesc); 1787e678fbd4SKarthikeyan Periyasamy rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(ab, ldesc); 1788d5c65159SKalle Valo 1789d5c65159SKalle Valo /* MSDU spans over multiple buffers because the length of the MSDU 1790d5c65159SKalle Valo * exceeds DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE. So assume the data 1791d5c65159SKalle Valo * in the first buf is of length DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE. 1792d5c65159SKalle Valo */ 1793d5c65159SKalle Valo skb_put(first, DP_RX_BUFFER_SIZE); 1794d2f510faSSriram R skb_pull(first, buf_first_hdr_len); 1795d5c65159SKalle Valo 179630679ec4SKarthikeyan Periyasamy /* When an MSDU spread over multiple buffers attention, MSDU_END and 179730679ec4SKarthikeyan Periyasamy * MPDU_END tlvs are valid only in the last buffer. Copy those tlvs. 179830679ec4SKarthikeyan Periyasamy */ 1799e678fbd4SKarthikeyan Periyasamy ath11k_dp_rx_desc_end_tlv_copy(ab, rxcb->rx_desc, ldesc); 180030679ec4SKarthikeyan Periyasamy 1801d2f510faSSriram R space_extra = msdu_len - (buf_first_len + skb_tailroom(first)); 1802d5c65159SKalle Valo if (space_extra > 0 && 1803d5c65159SKalle Valo (pskb_expand_head(first, 0, space_extra, GFP_ATOMIC) < 0)) { 1804d5c65159SKalle Valo /* Free up all buffers of the MSDU */ 1805d5c65159SKalle Valo while ((skb = __skb_dequeue(msdu_list)) != NULL) { 1806d5c65159SKalle Valo rxcb = ATH11K_SKB_RXCB(skb); 1807d5c65159SKalle Valo if (!rxcb->is_continuation) { 1808d5c65159SKalle Valo dev_kfree_skb_any(skb); 1809d5c65159SKalle Valo break; 1810d5c65159SKalle Valo } 1811d5c65159SKalle Valo dev_kfree_skb_any(skb); 1812d5c65159SKalle Valo } 1813d5c65159SKalle Valo return -ENOMEM; 1814d5c65159SKalle Valo } 1815d5c65159SKalle Valo 1816d2f510faSSriram R rem_len = msdu_len - buf_first_len; 1817d5c65159SKalle Valo while ((skb = __skb_dequeue(msdu_list)) != NULL && rem_len > 0) { 1818d5c65159SKalle Valo rxcb = ATH11K_SKB_RXCB(skb); 1819d5c65159SKalle Valo if (rxcb->is_continuation) 1820e678fbd4SKarthikeyan Periyasamy buf_len = DP_RX_BUFFER_SIZE - hal_rx_desc_sz; 1821d5c65159SKalle Valo else 1822d5c65159SKalle Valo buf_len = rem_len; 1823d5c65159SKalle Valo 1824e678fbd4SKarthikeyan Periyasamy if (buf_len > (DP_RX_BUFFER_SIZE - hal_rx_desc_sz)) { 1825d5c65159SKalle Valo WARN_ON_ONCE(1); 1826d5c65159SKalle Valo dev_kfree_skb_any(skb); 1827d5c65159SKalle Valo return -EINVAL; 1828d5c65159SKalle Valo } 1829d5c65159SKalle Valo 1830e678fbd4SKarthikeyan Periyasamy skb_put(skb, buf_len + hal_rx_desc_sz); 1831e678fbd4SKarthikeyan Periyasamy skb_pull(skb, hal_rx_desc_sz); 1832d5c65159SKalle Valo skb_copy_from_linear_data(skb, skb_put(first, buf_len), 1833d5c65159SKalle Valo buf_len); 1834d5c65159SKalle Valo dev_kfree_skb_any(skb); 1835d5c65159SKalle Valo 1836d5c65159SKalle Valo rem_len -= buf_len; 1837d5c65159SKalle Valo if (!rxcb->is_continuation) 1838d5c65159SKalle Valo break; 1839d5c65159SKalle Valo } 1840d5c65159SKalle Valo 1841d5c65159SKalle Valo return 0; 1842d5c65159SKalle Valo } 1843d5c65159SKalle Valo 1844d5c65159SKalle Valo static struct sk_buff *ath11k_dp_rx_get_msdu_last_buf(struct sk_buff_head *msdu_list, 1845d5c65159SKalle Valo struct sk_buff *first) 1846d5c65159SKalle Valo { 1847d5c65159SKalle Valo struct sk_buff *skb; 1848d5c65159SKalle Valo struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(first); 1849d5c65159SKalle Valo 1850d5c65159SKalle Valo if (!rxcb->is_continuation) 1851d5c65159SKalle Valo return first; 1852d5c65159SKalle Valo 1853d5c65159SKalle Valo skb_queue_walk(msdu_list, skb) { 1854d5c65159SKalle Valo rxcb = ATH11K_SKB_RXCB(skb); 1855d5c65159SKalle Valo if (!rxcb->is_continuation) 1856d5c65159SKalle Valo return skb; 1857d5c65159SKalle Valo } 1858d5c65159SKalle Valo 1859d5c65159SKalle Valo return NULL; 1860d5c65159SKalle Valo } 1861d5c65159SKalle Valo 1862e678fbd4SKarthikeyan Periyasamy static void ath11k_dp_rx_h_csum_offload(struct ath11k *ar, struct sk_buff *msdu) 1863d5c65159SKalle Valo { 1864d5c65159SKalle Valo struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 1865e678fbd4SKarthikeyan Periyasamy struct rx_attention *rx_attention; 1866d5c65159SKalle Valo bool ip_csum_fail, l4_csum_fail; 1867d5c65159SKalle Valo 1868e678fbd4SKarthikeyan Periyasamy rx_attention = ath11k_dp_rx_get_attention(ar->ab, rxcb->rx_desc); 1869e678fbd4SKarthikeyan Periyasamy ip_csum_fail = ath11k_dp_rx_h_attn_ip_cksum_fail(rx_attention); 1870e678fbd4SKarthikeyan Periyasamy l4_csum_fail = ath11k_dp_rx_h_attn_l4_cksum_fail(rx_attention); 1871d5c65159SKalle Valo 1872d5c65159SKalle Valo msdu->ip_summed = (ip_csum_fail || l4_csum_fail) ? 1873d5c65159SKalle Valo CHECKSUM_NONE : CHECKSUM_UNNECESSARY; 1874d5c65159SKalle Valo } 1875d5c65159SKalle Valo 1876d5c65159SKalle Valo static int ath11k_dp_rx_crypto_mic_len(struct ath11k *ar, 1877d5c65159SKalle Valo enum hal_encrypt_type enctype) 1878d5c65159SKalle Valo { 1879d5c65159SKalle Valo switch (enctype) { 1880d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_OPEN: 1881d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_TKIP_NO_MIC: 1882d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_TKIP_MIC: 1883d5c65159SKalle Valo return 0; 1884d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_CCMP_128: 1885d5c65159SKalle Valo return IEEE80211_CCMP_MIC_LEN; 1886d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_CCMP_256: 1887d5c65159SKalle Valo return IEEE80211_CCMP_256_MIC_LEN; 1888d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_GCMP_128: 1889d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_AES_GCMP_256: 1890d5c65159SKalle Valo return IEEE80211_GCMP_MIC_LEN; 1891d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_WEP_40: 1892d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_WEP_104: 1893d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_WEP_128: 1894d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4: 1895d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_WAPI: 1896d5c65159SKalle Valo break; 1897d5c65159SKalle Valo } 1898d5c65159SKalle Valo 1899d5c65159SKalle Valo ath11k_warn(ar->ab, "unsupported encryption type %d for mic len\n", enctype); 1900d5c65159SKalle Valo return 0; 1901d5c65159SKalle Valo } 1902d5c65159SKalle Valo 1903d5c65159SKalle Valo static int ath11k_dp_rx_crypto_param_len(struct ath11k *ar, 1904d5c65159SKalle Valo enum hal_encrypt_type enctype) 1905d5c65159SKalle Valo { 1906d5c65159SKalle Valo switch (enctype) { 1907d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_OPEN: 1908d5c65159SKalle Valo return 0; 1909d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_TKIP_NO_MIC: 1910d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_TKIP_MIC: 1911d5c65159SKalle Valo return IEEE80211_TKIP_IV_LEN; 1912d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_CCMP_128: 1913d5c65159SKalle Valo return IEEE80211_CCMP_HDR_LEN; 1914d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_CCMP_256: 1915d5c65159SKalle Valo return IEEE80211_CCMP_256_HDR_LEN; 1916d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_GCMP_128: 1917d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_AES_GCMP_256: 1918d5c65159SKalle Valo return IEEE80211_GCMP_HDR_LEN; 1919d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_WEP_40: 1920d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_WEP_104: 1921d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_WEP_128: 1922d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4: 1923d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_WAPI: 1924d5c65159SKalle Valo break; 1925d5c65159SKalle Valo } 1926d5c65159SKalle Valo 1927d5c65159SKalle Valo ath11k_warn(ar->ab, "unsupported encryption type %d\n", enctype); 1928d5c65159SKalle Valo return 0; 1929d5c65159SKalle Valo } 1930d5c65159SKalle Valo 1931d5c65159SKalle Valo static int ath11k_dp_rx_crypto_icv_len(struct ath11k *ar, 1932d5c65159SKalle Valo enum hal_encrypt_type enctype) 1933d5c65159SKalle Valo { 1934d5c65159SKalle Valo switch (enctype) { 1935d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_OPEN: 1936d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_CCMP_128: 1937d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_CCMP_256: 1938d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_GCMP_128: 1939d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_AES_GCMP_256: 1940d5c65159SKalle Valo return 0; 1941d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_TKIP_NO_MIC: 1942d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_TKIP_MIC: 1943d5c65159SKalle Valo return IEEE80211_TKIP_ICV_LEN; 1944d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_WEP_40: 1945d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_WEP_104: 1946d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_WEP_128: 1947d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4: 1948d5c65159SKalle Valo case HAL_ENCRYPT_TYPE_WAPI: 1949d5c65159SKalle Valo break; 1950d5c65159SKalle Valo } 1951d5c65159SKalle Valo 1952d5c65159SKalle Valo ath11k_warn(ar->ab, "unsupported encryption type %d\n", enctype); 1953d5c65159SKalle Valo return 0; 1954d5c65159SKalle Valo } 1955d5c65159SKalle Valo 1956d5c65159SKalle Valo static void ath11k_dp_rx_h_undecap_nwifi(struct ath11k *ar, 1957d5c65159SKalle Valo struct sk_buff *msdu, 1958d5c65159SKalle Valo u8 *first_hdr, 1959d5c65159SKalle Valo enum hal_encrypt_type enctype, 1960d5c65159SKalle Valo struct ieee80211_rx_status *status) 1961d5c65159SKalle Valo { 1962acc79d98SSriram R struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 1963acc79d98SSriram R u8 decap_hdr[DP_MAX_NWIFI_HDR_LEN]; 1964d5c65159SKalle Valo struct ieee80211_hdr *hdr; 1965d5c65159SKalle Valo size_t hdr_len; 1966d5c65159SKalle Valo u8 da[ETH_ALEN]; 1967d5c65159SKalle Valo u8 sa[ETH_ALEN]; 1968acc79d98SSriram R u16 qos_ctl = 0; 1969acc79d98SSriram R u8 *qos; 1970d5c65159SKalle Valo 1971acc79d98SSriram R /* copy SA & DA and pull decapped header */ 1972d5c65159SKalle Valo hdr = (struct ieee80211_hdr *)msdu->data; 1973acc79d98SSriram R hdr_len = ieee80211_hdrlen(hdr->frame_control); 1974d5c65159SKalle Valo ether_addr_copy(da, ieee80211_get_DA(hdr)); 1975d5c65159SKalle Valo ether_addr_copy(sa, ieee80211_get_SA(hdr)); 1976d5c65159SKalle Valo skb_pull(msdu, ieee80211_hdrlen(hdr->frame_control)); 1977d5c65159SKalle Valo 1978acc79d98SSriram R if (rxcb->is_first_msdu) { 1979acc79d98SSriram R /* original 802.11 header is valid for the first msdu 1980acc79d98SSriram R * hence we can reuse the same header 1981acc79d98SSriram R */ 1982d5c65159SKalle Valo hdr = (struct ieee80211_hdr *)first_hdr; 1983d5c65159SKalle Valo hdr_len = ieee80211_hdrlen(hdr->frame_control); 1984d5c65159SKalle Valo 1985acc79d98SSriram R /* Each A-MSDU subframe will be reported as a separate MSDU, 1986acc79d98SSriram R * so strip the A-MSDU bit from QoS Ctl. 1987acc79d98SSriram R */ 1988acc79d98SSriram R if (ieee80211_is_data_qos(hdr->frame_control)) { 1989acc79d98SSriram R qos = ieee80211_get_qos_ctl(hdr); 1990acc79d98SSriram R qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; 1991acc79d98SSriram R } 1992acc79d98SSriram R } else { 1993acc79d98SSriram R /* Rebuild qos header if this is a middle/last msdu */ 1994acc79d98SSriram R hdr->frame_control |= __cpu_to_le16(IEEE80211_STYPE_QOS_DATA); 1995acc79d98SSriram R 1996acc79d98SSriram R /* Reset the order bit as the HT_Control header is stripped */ 1997acc79d98SSriram R hdr->frame_control &= ~(__cpu_to_le16(IEEE80211_FCTL_ORDER)); 1998acc79d98SSriram R 1999acc79d98SSriram R qos_ctl = rxcb->tid; 2000acc79d98SSriram R 2001e678fbd4SKarthikeyan Periyasamy if (ath11k_dp_rx_h_msdu_start_mesh_ctl_present(ar->ab, rxcb->rx_desc)) 2002acc79d98SSriram R qos_ctl |= IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT; 2003acc79d98SSriram R 2004acc79d98SSriram R /* TODO Add other QoS ctl fields when required */ 2005acc79d98SSriram R 2006acc79d98SSriram R /* copy decap header before overwriting for reuse below */ 2007acc79d98SSriram R memcpy(decap_hdr, (uint8_t *)hdr, hdr_len); 2008acc79d98SSriram R } 2009acc79d98SSriram R 2010d5c65159SKalle Valo if (!(status->flag & RX_FLAG_IV_STRIPPED)) { 2011d5c65159SKalle Valo memcpy(skb_push(msdu, 2012d5c65159SKalle Valo ath11k_dp_rx_crypto_param_len(ar, enctype)), 2013d5c65159SKalle Valo (void *)hdr + hdr_len, 2014d5c65159SKalle Valo ath11k_dp_rx_crypto_param_len(ar, enctype)); 2015d5c65159SKalle Valo } 2016d5c65159SKalle Valo 2017acc79d98SSriram R if (!rxcb->is_first_msdu) { 2018acc79d98SSriram R memcpy(skb_push(msdu, 2019acc79d98SSriram R IEEE80211_QOS_CTL_LEN), &qos_ctl, 2020acc79d98SSriram R IEEE80211_QOS_CTL_LEN); 2021acc79d98SSriram R memcpy(skb_push(msdu, hdr_len), decap_hdr, hdr_len); 2022acc79d98SSriram R return; 2023acc79d98SSriram R } 2024acc79d98SSriram R 2025d5c65159SKalle Valo memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); 2026d5c65159SKalle Valo 2027d5c65159SKalle Valo /* original 802.11 header has a different DA and in 2028d5c65159SKalle Valo * case of 4addr it may also have different SA 2029d5c65159SKalle Valo */ 2030d5c65159SKalle Valo hdr = (struct ieee80211_hdr *)msdu->data; 2031d5c65159SKalle Valo ether_addr_copy(ieee80211_get_DA(hdr), da); 2032d5c65159SKalle Valo ether_addr_copy(ieee80211_get_SA(hdr), sa); 2033d5c65159SKalle Valo } 2034d5c65159SKalle Valo 2035d5c65159SKalle Valo static void ath11k_dp_rx_h_undecap_raw(struct ath11k *ar, struct sk_buff *msdu, 2036d5c65159SKalle Valo enum hal_encrypt_type enctype, 2037d5c65159SKalle Valo struct ieee80211_rx_status *status, 2038d5c65159SKalle Valo bool decrypted) 2039d5c65159SKalle Valo { 2040d5c65159SKalle Valo struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 2041d5c65159SKalle Valo struct ieee80211_hdr *hdr; 2042d5c65159SKalle Valo size_t hdr_len; 2043d5c65159SKalle Valo size_t crypto_len; 2044d5c65159SKalle Valo 2045d5c65159SKalle Valo if (!rxcb->is_first_msdu || 2046d5c65159SKalle Valo !(rxcb->is_first_msdu && rxcb->is_last_msdu)) { 2047d5c65159SKalle Valo WARN_ON_ONCE(1); 2048d5c65159SKalle Valo return; 2049d5c65159SKalle Valo } 2050d5c65159SKalle Valo 2051d5c65159SKalle Valo skb_trim(msdu, msdu->len - FCS_LEN); 2052d5c65159SKalle Valo 2053d5c65159SKalle Valo if (!decrypted) 2054d5c65159SKalle Valo return; 2055d5c65159SKalle Valo 2056d5c65159SKalle Valo hdr = (void *)msdu->data; 2057d5c65159SKalle Valo 2058d5c65159SKalle Valo /* Tail */ 2059d5c65159SKalle Valo if (status->flag & RX_FLAG_IV_STRIPPED) { 2060d5c65159SKalle Valo skb_trim(msdu, msdu->len - 2061d5c65159SKalle Valo ath11k_dp_rx_crypto_mic_len(ar, enctype)); 2062d5c65159SKalle Valo 2063d5c65159SKalle Valo skb_trim(msdu, msdu->len - 2064d5c65159SKalle Valo ath11k_dp_rx_crypto_icv_len(ar, enctype)); 2065d5c65159SKalle Valo } else { 2066d5c65159SKalle Valo /* MIC */ 2067d5c65159SKalle Valo if (status->flag & RX_FLAG_MIC_STRIPPED) 2068d5c65159SKalle Valo skb_trim(msdu, msdu->len - 2069d5c65159SKalle Valo ath11k_dp_rx_crypto_mic_len(ar, enctype)); 2070d5c65159SKalle Valo 2071d5c65159SKalle Valo /* ICV */ 2072d5c65159SKalle Valo if (status->flag & RX_FLAG_ICV_STRIPPED) 2073d5c65159SKalle Valo skb_trim(msdu, msdu->len - 2074d5c65159SKalle Valo ath11k_dp_rx_crypto_icv_len(ar, enctype)); 2075d5c65159SKalle Valo } 2076d5c65159SKalle Valo 2077d5c65159SKalle Valo /* MMIC */ 2078d5c65159SKalle Valo if ((status->flag & RX_FLAG_MMIC_STRIPPED) && 2079d5c65159SKalle Valo !ieee80211_has_morefrags(hdr->frame_control) && 2080d5c65159SKalle Valo enctype == HAL_ENCRYPT_TYPE_TKIP_MIC) 2081d5c65159SKalle Valo skb_trim(msdu, msdu->len - IEEE80211_CCMP_MIC_LEN); 2082d5c65159SKalle Valo 2083d5c65159SKalle Valo /* Head */ 2084d5c65159SKalle Valo if (status->flag & RX_FLAG_IV_STRIPPED) { 2085d5c65159SKalle Valo hdr_len = ieee80211_hdrlen(hdr->frame_control); 2086d5c65159SKalle Valo crypto_len = ath11k_dp_rx_crypto_param_len(ar, enctype); 2087d5c65159SKalle Valo 2088d5c65159SKalle Valo memmove((void *)msdu->data + crypto_len, 2089d5c65159SKalle Valo (void *)msdu->data, hdr_len); 2090d5c65159SKalle Valo skb_pull(msdu, crypto_len); 2091d5c65159SKalle Valo } 2092d5c65159SKalle Valo } 2093d5c65159SKalle Valo 2094d5c65159SKalle Valo static void *ath11k_dp_rx_h_find_rfc1042(struct ath11k *ar, 2095d5c65159SKalle Valo struct sk_buff *msdu, 2096d5c65159SKalle Valo enum hal_encrypt_type enctype) 2097d5c65159SKalle Valo { 2098d5c65159SKalle Valo struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 2099d5c65159SKalle Valo struct ieee80211_hdr *hdr; 2100d5c65159SKalle Valo size_t hdr_len, crypto_len; 2101d5c65159SKalle Valo void *rfc1042; 2102d5c65159SKalle Valo bool is_amsdu; 2103d5c65159SKalle Valo 2104d5c65159SKalle Valo is_amsdu = !(rxcb->is_first_msdu && rxcb->is_last_msdu); 2105e678fbd4SKarthikeyan Periyasamy hdr = (struct ieee80211_hdr *)ath11k_dp_rx_h_80211_hdr(ar->ab, rxcb->rx_desc); 2106d5c65159SKalle Valo rfc1042 = hdr; 2107d5c65159SKalle Valo 2108d5c65159SKalle Valo if (rxcb->is_first_msdu) { 2109d5c65159SKalle Valo hdr_len = ieee80211_hdrlen(hdr->frame_control); 2110d5c65159SKalle Valo crypto_len = ath11k_dp_rx_crypto_param_len(ar, enctype); 2111d5c65159SKalle Valo 2112d5c65159SKalle Valo rfc1042 += hdr_len + crypto_len; 2113d5c65159SKalle Valo } 2114d5c65159SKalle Valo 2115d5c65159SKalle Valo if (is_amsdu) 2116d5c65159SKalle Valo rfc1042 += sizeof(struct ath11k_dp_amsdu_subframe_hdr); 2117d5c65159SKalle Valo 2118d5c65159SKalle Valo return rfc1042; 2119d5c65159SKalle Valo } 2120d5c65159SKalle Valo 2121d5c65159SKalle Valo static void ath11k_dp_rx_h_undecap_eth(struct ath11k *ar, 2122d5c65159SKalle Valo struct sk_buff *msdu, 2123d5c65159SKalle Valo u8 *first_hdr, 2124d5c65159SKalle Valo enum hal_encrypt_type enctype, 2125d5c65159SKalle Valo struct ieee80211_rx_status *status) 2126d5c65159SKalle Valo { 2127d5c65159SKalle Valo struct ieee80211_hdr *hdr; 2128d5c65159SKalle Valo struct ethhdr *eth; 2129d5c65159SKalle Valo size_t hdr_len; 2130d5c65159SKalle Valo u8 da[ETH_ALEN]; 2131d5c65159SKalle Valo u8 sa[ETH_ALEN]; 2132d5c65159SKalle Valo void *rfc1042; 2133d5c65159SKalle Valo 2134d5c65159SKalle Valo rfc1042 = ath11k_dp_rx_h_find_rfc1042(ar, msdu, enctype); 2135d5c65159SKalle Valo if (WARN_ON_ONCE(!rfc1042)) 2136d5c65159SKalle Valo return; 2137d5c65159SKalle Valo 2138d5c65159SKalle Valo /* pull decapped header and copy SA & DA */ 2139d5c65159SKalle Valo eth = (struct ethhdr *)msdu->data; 2140d5c65159SKalle Valo ether_addr_copy(da, eth->h_dest); 2141d5c65159SKalle Valo ether_addr_copy(sa, eth->h_source); 2142d5c65159SKalle Valo skb_pull(msdu, sizeof(struct ethhdr)); 2143d5c65159SKalle Valo 2144d5c65159SKalle Valo /* push rfc1042/llc/snap */ 2145d5c65159SKalle Valo memcpy(skb_push(msdu, sizeof(struct ath11k_dp_rfc1042_hdr)), rfc1042, 2146d5c65159SKalle Valo sizeof(struct ath11k_dp_rfc1042_hdr)); 2147d5c65159SKalle Valo 2148d5c65159SKalle Valo /* push original 802.11 header */ 2149d5c65159SKalle Valo hdr = (struct ieee80211_hdr *)first_hdr; 2150d5c65159SKalle Valo hdr_len = ieee80211_hdrlen(hdr->frame_control); 2151d5c65159SKalle Valo 2152d5c65159SKalle Valo if (!(status->flag & RX_FLAG_IV_STRIPPED)) { 2153d5c65159SKalle Valo memcpy(skb_push(msdu, 2154d5c65159SKalle Valo ath11k_dp_rx_crypto_param_len(ar, enctype)), 2155d5c65159SKalle Valo (void *)hdr + hdr_len, 2156d5c65159SKalle Valo ath11k_dp_rx_crypto_param_len(ar, enctype)); 2157d5c65159SKalle Valo } 2158d5c65159SKalle Valo 2159d5c65159SKalle Valo memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); 2160d5c65159SKalle Valo 2161d5c65159SKalle Valo /* original 802.11 header has a different DA and in 2162d5c65159SKalle Valo * case of 4addr it may also have different SA 2163d5c65159SKalle Valo */ 2164d5c65159SKalle Valo hdr = (struct ieee80211_hdr *)msdu->data; 2165d5c65159SKalle Valo ether_addr_copy(ieee80211_get_DA(hdr), da); 2166d5c65159SKalle Valo ether_addr_copy(ieee80211_get_SA(hdr), sa); 2167d5c65159SKalle Valo } 2168d5c65159SKalle Valo 2169d5c65159SKalle Valo static void ath11k_dp_rx_h_undecap(struct ath11k *ar, struct sk_buff *msdu, 2170d5c65159SKalle Valo struct hal_rx_desc *rx_desc, 2171d5c65159SKalle Valo enum hal_encrypt_type enctype, 2172d5c65159SKalle Valo struct ieee80211_rx_status *status, 2173d5c65159SKalle Valo bool decrypted) 2174d5c65159SKalle Valo { 2175d5c65159SKalle Valo u8 *first_hdr; 2176d5c65159SKalle Valo u8 decap; 21772167fa60SSriram R struct ethhdr *ehdr; 2178d5c65159SKalle Valo 2179e678fbd4SKarthikeyan Periyasamy first_hdr = ath11k_dp_rx_h_80211_hdr(ar->ab, rx_desc); 2180e678fbd4SKarthikeyan Periyasamy decap = ath11k_dp_rx_h_msdu_start_decap_type(ar->ab, rx_desc); 2181d5c65159SKalle Valo 2182d5c65159SKalle Valo switch (decap) { 2183d5c65159SKalle Valo case DP_RX_DECAP_TYPE_NATIVE_WIFI: 2184d5c65159SKalle Valo ath11k_dp_rx_h_undecap_nwifi(ar, msdu, first_hdr, 2185d5c65159SKalle Valo enctype, status); 2186d5c65159SKalle Valo break; 2187d5c65159SKalle Valo case DP_RX_DECAP_TYPE_RAW: 2188d5c65159SKalle Valo ath11k_dp_rx_h_undecap_raw(ar, msdu, enctype, status, 2189d5c65159SKalle Valo decrypted); 2190d5c65159SKalle Valo break; 2191d5c65159SKalle Valo case DP_RX_DECAP_TYPE_ETHERNET2_DIX: 21922167fa60SSriram R ehdr = (struct ethhdr *)msdu->data; 21932167fa60SSriram R 21942167fa60SSriram R /* mac80211 allows fast path only for authorized STA */ 21952167fa60SSriram R if (ehdr->h_proto == cpu_to_be16(ETH_P_PAE)) { 21962167fa60SSriram R ATH11K_SKB_RXCB(msdu)->is_eapol = true; 21972167fa60SSriram R ath11k_dp_rx_h_undecap_eth(ar, msdu, first_hdr, 21982167fa60SSriram R enctype, status); 21992167fa60SSriram R break; 22002167fa60SSriram R } 22012167fa60SSriram R 22022167fa60SSriram R /* PN for mcast packets will be validated in mac80211; 22032167fa60SSriram R * remove eth header and add 802.11 header. 22042167fa60SSriram R */ 22052167fa60SSriram R if (ATH11K_SKB_RXCB(msdu)->is_mcbc && decrypted) 2206d5c65159SKalle Valo ath11k_dp_rx_h_undecap_eth(ar, msdu, first_hdr, 2207d5c65159SKalle Valo enctype, status); 2208d5c65159SKalle Valo break; 2209d5c65159SKalle Valo case DP_RX_DECAP_TYPE_8023: 2210d5c65159SKalle Valo /* TODO: Handle undecap for these formats */ 2211d5c65159SKalle Valo break; 2212d5c65159SKalle Valo } 2213d5c65159SKalle Valo } 2214d5c65159SKalle Valo 22152167fa60SSriram R static struct ath11k_peer * 22162167fa60SSriram R ath11k_dp_rx_h_find_peer(struct ath11k_base *ab, struct sk_buff *msdu) 22172167fa60SSriram R { 22182167fa60SSriram R struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 22192167fa60SSriram R struct hal_rx_desc *rx_desc = rxcb->rx_desc; 22202167fa60SSriram R struct ath11k_peer *peer = NULL; 22212167fa60SSriram R 22222167fa60SSriram R lockdep_assert_held(&ab->base_lock); 22232167fa60SSriram R 22242167fa60SSriram R if (rxcb->peer_id) 22252167fa60SSriram R peer = ath11k_peer_find_by_id(ab, rxcb->peer_id); 22262167fa60SSriram R 22272167fa60SSriram R if (peer) 22282167fa60SSriram R return peer; 22292167fa60SSriram R 22302167fa60SSriram R if (!rx_desc || !(ath11k_dp_rxdesc_mac_addr2_valid(ab, rx_desc))) 22312167fa60SSriram R return NULL; 22322167fa60SSriram R 22332167fa60SSriram R peer = ath11k_peer_find_by_addr(ab, 22342167fa60SSriram R ath11k_dp_rxdesc_mpdu_start_addr2(ab, rx_desc)); 22352167fa60SSriram R return peer; 22362167fa60SSriram R } 22372167fa60SSriram R 2238d5c65159SKalle Valo static void ath11k_dp_rx_h_mpdu(struct ath11k *ar, 2239acc79d98SSriram R struct sk_buff *msdu, 2240d5c65159SKalle Valo struct hal_rx_desc *rx_desc, 2241d5c65159SKalle Valo struct ieee80211_rx_status *rx_status) 2242d5c65159SKalle Valo { 22432167fa60SSriram R bool fill_crypto_hdr; 2244d5c65159SKalle Valo enum hal_encrypt_type enctype; 2245acc79d98SSriram R bool is_decrypted = false; 22462167fa60SSriram R struct ath11k_skb_rxcb *rxcb; 2247acc79d98SSriram R struct ieee80211_hdr *hdr; 2248acc79d98SSriram R struct ath11k_peer *peer; 2249e678fbd4SKarthikeyan Periyasamy struct rx_attention *rx_attention; 2250d5c65159SKalle Valo u32 err_bitmap; 2251d5c65159SKalle Valo 22521441b2f2SManikanta Pubbisetty /* PN for multicast packets will be checked in mac80211 */ 22532167fa60SSriram R rxcb = ATH11K_SKB_RXCB(msdu); 22542167fa60SSriram R fill_crypto_hdr = ath11k_dp_rx_h_attn_is_mcbc(ar->ab, rx_desc); 22552167fa60SSriram R rxcb->is_mcbc = fill_crypto_hdr; 2256acc79d98SSriram R 22572167fa60SSriram R if (rxcb->is_mcbc) { 22582167fa60SSriram R rxcb->peer_id = ath11k_dp_rx_h_mpdu_start_peer_id(ar->ab, rx_desc); 22592167fa60SSriram R rxcb->seq_no = ath11k_dp_rx_h_mpdu_start_seq_no(ar->ab, rx_desc); 22602167fa60SSriram R } 22611441b2f2SManikanta Pubbisetty 2262acc79d98SSriram R spin_lock_bh(&ar->ab->base_lock); 22632167fa60SSriram R peer = ath11k_dp_rx_h_find_peer(ar->ab, msdu); 2264acc79d98SSriram R if (peer) { 22652167fa60SSriram R if (rxcb->is_mcbc) 2266acc79d98SSriram R enctype = peer->sec_type_grp; 2267acc79d98SSriram R else 2268acc79d98SSriram R enctype = peer->sec_type; 2269acc79d98SSriram R } else { 22702167fa60SSriram R enctype = ath11k_dp_rx_h_mpdu_start_enctype(ar->ab, rx_desc); 2271acc79d98SSriram R } 2272acc79d98SSriram R spin_unlock_bh(&ar->ab->base_lock); 2273d5c65159SKalle Valo 2274e678fbd4SKarthikeyan Periyasamy rx_attention = ath11k_dp_rx_get_attention(ar->ab, rx_desc); 2275e678fbd4SKarthikeyan Periyasamy err_bitmap = ath11k_dp_rx_h_attn_mpdu_err(rx_attention); 2276aa2092a9SVenkateswara Naralasetty if (enctype != HAL_ENCRYPT_TYPE_OPEN && !err_bitmap) 2277e678fbd4SKarthikeyan Periyasamy is_decrypted = ath11k_dp_rx_h_attn_is_decrypted(rx_attention); 2278d5c65159SKalle Valo 2279acc79d98SSriram R /* Clear per-MPDU flags while leaving per-PPDU flags intact */ 2280d5c65159SKalle Valo rx_status->flag &= ~(RX_FLAG_FAILED_FCS_CRC | 2281d5c65159SKalle Valo RX_FLAG_MMIC_ERROR | 2282d5c65159SKalle Valo RX_FLAG_DECRYPTED | 2283d5c65159SKalle Valo RX_FLAG_IV_STRIPPED | 2284d5c65159SKalle Valo RX_FLAG_MMIC_STRIPPED); 2285d5c65159SKalle Valo 2286d5c65159SKalle Valo if (err_bitmap & DP_RX_MPDU_ERR_FCS) 2287d5c65159SKalle Valo rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; 2288d5c65159SKalle Valo if (err_bitmap & DP_RX_MPDU_ERR_TKIP_MIC) 2289d5c65159SKalle Valo rx_status->flag |= RX_FLAG_MMIC_ERROR; 2290d5c65159SKalle Valo 22911441b2f2SManikanta Pubbisetty if (is_decrypted) { 22921441b2f2SManikanta Pubbisetty rx_status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_MMIC_STRIPPED; 22931441b2f2SManikanta Pubbisetty 22941441b2f2SManikanta Pubbisetty if (fill_crypto_hdr) 22951441b2f2SManikanta Pubbisetty rx_status->flag |= RX_FLAG_MIC_STRIPPED | 22961441b2f2SManikanta Pubbisetty RX_FLAG_ICV_STRIPPED; 22971441b2f2SManikanta Pubbisetty else 22981441b2f2SManikanta Pubbisetty rx_status->flag |= RX_FLAG_IV_STRIPPED | 22991441b2f2SManikanta Pubbisetty RX_FLAG_PN_VALIDATED; 23001441b2f2SManikanta Pubbisetty } 2301d5c65159SKalle Valo 2302e678fbd4SKarthikeyan Periyasamy ath11k_dp_rx_h_csum_offload(ar, msdu); 2303d5c65159SKalle Valo ath11k_dp_rx_h_undecap(ar, msdu, rx_desc, 2304d5c65159SKalle Valo enctype, rx_status, is_decrypted); 23051441b2f2SManikanta Pubbisetty 23061441b2f2SManikanta Pubbisetty if (!is_decrypted || fill_crypto_hdr) 2307acc79d98SSriram R return; 23081441b2f2SManikanta Pubbisetty 23092167fa60SSriram R if (ath11k_dp_rx_h_msdu_start_decap_type(ar->ab, rx_desc) != 23102167fa60SSriram R DP_RX_DECAP_TYPE_ETHERNET2_DIX) { 23111441b2f2SManikanta Pubbisetty hdr = (void *)msdu->data; 23121441b2f2SManikanta Pubbisetty hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); 2313d5c65159SKalle Valo } 23142167fa60SSriram R } 2315d5c65159SKalle Valo 2316d5c65159SKalle Valo static void ath11k_dp_rx_h_rate(struct ath11k *ar, struct hal_rx_desc *rx_desc, 2317d5c65159SKalle Valo struct ieee80211_rx_status *rx_status) 2318d5c65159SKalle Valo { 2319d5c65159SKalle Valo struct ieee80211_supported_band *sband; 2320d5c65159SKalle Valo enum rx_msdu_start_pkt_type pkt_type; 2321d5c65159SKalle Valo u8 bw; 2322d5c65159SKalle Valo u8 rate_mcs, nss; 2323d5c65159SKalle Valo u8 sgi; 2324b3febdccSP Praneesh bool is_cck, is_ldpc; 2325d5c65159SKalle Valo 2326e678fbd4SKarthikeyan Periyasamy pkt_type = ath11k_dp_rx_h_msdu_start_pkt_type(ar->ab, rx_desc); 2327e678fbd4SKarthikeyan Periyasamy bw = ath11k_dp_rx_h_msdu_start_rx_bw(ar->ab, rx_desc); 2328e678fbd4SKarthikeyan Periyasamy rate_mcs = ath11k_dp_rx_h_msdu_start_rate_mcs(ar->ab, rx_desc); 2329e678fbd4SKarthikeyan Periyasamy nss = ath11k_dp_rx_h_msdu_start_nss(ar->ab, rx_desc); 2330e678fbd4SKarthikeyan Periyasamy sgi = ath11k_dp_rx_h_msdu_start_sgi(ar->ab, rx_desc); 2331d5c65159SKalle Valo 2332d5c65159SKalle Valo switch (pkt_type) { 2333d5c65159SKalle Valo case RX_MSDU_START_PKT_TYPE_11A: 2334d5c65159SKalle Valo case RX_MSDU_START_PKT_TYPE_11B: 2335d5c65159SKalle Valo is_cck = (pkt_type == RX_MSDU_START_PKT_TYPE_11B); 2336d5c65159SKalle Valo sband = &ar->mac.sbands[rx_status->band]; 2337d5c65159SKalle Valo rx_status->rate_idx = ath11k_mac_hw_rate_to_idx(sband, rate_mcs, 2338d5c65159SKalle Valo is_cck); 2339d5c65159SKalle Valo break; 2340d5c65159SKalle Valo case RX_MSDU_START_PKT_TYPE_11N: 2341d5c65159SKalle Valo rx_status->encoding = RX_ENC_HT; 2342d5c65159SKalle Valo if (rate_mcs > ATH11K_HT_MCS_MAX) { 2343d5c65159SKalle Valo ath11k_warn(ar->ab, 2344d5c65159SKalle Valo "Received with invalid mcs in HT mode %d\n", 2345d5c65159SKalle Valo rate_mcs); 2346d5c65159SKalle Valo break; 2347d5c65159SKalle Valo } 2348d5c65159SKalle Valo rx_status->rate_idx = rate_mcs + (8 * (nss - 1)); 2349d5c65159SKalle Valo if (sgi) 2350d5c65159SKalle Valo rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; 235139e81c6aSTamizh chelvam rx_status->bw = ath11k_mac_bw_to_mac80211_bw(bw); 2352d5c65159SKalle Valo break; 2353d5c65159SKalle Valo case RX_MSDU_START_PKT_TYPE_11AC: 2354d5c65159SKalle Valo rx_status->encoding = RX_ENC_VHT; 2355d5c65159SKalle Valo rx_status->rate_idx = rate_mcs; 2356d5c65159SKalle Valo if (rate_mcs > ATH11K_VHT_MCS_MAX) { 2357d5c65159SKalle Valo ath11k_warn(ar->ab, 2358d5c65159SKalle Valo "Received with invalid mcs in VHT mode %d\n", 2359d5c65159SKalle Valo rate_mcs); 2360d5c65159SKalle Valo break; 2361d5c65159SKalle Valo } 2362d5c65159SKalle Valo rx_status->nss = nss; 2363d5c65159SKalle Valo if (sgi) 2364d5c65159SKalle Valo rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; 236539e81c6aSTamizh chelvam rx_status->bw = ath11k_mac_bw_to_mac80211_bw(bw); 2366b3febdccSP Praneesh is_ldpc = ath11k_dp_rx_h_msdu_start_ldpc_support(ar->ab, rx_desc); 2367b3febdccSP Praneesh if (is_ldpc) 2368b3febdccSP Praneesh rx_status->enc_flags |= RX_ENC_FLAG_LDPC; 2369d5c65159SKalle Valo break; 2370d5c65159SKalle Valo case RX_MSDU_START_PKT_TYPE_11AX: 2371d5c65159SKalle Valo rx_status->rate_idx = rate_mcs; 2372d5c65159SKalle Valo if (rate_mcs > ATH11K_HE_MCS_MAX) { 2373d5c65159SKalle Valo ath11k_warn(ar->ab, 2374d5c65159SKalle Valo "Received with invalid mcs in HE mode %d\n", 2375d5c65159SKalle Valo rate_mcs); 2376d5c65159SKalle Valo break; 2377d5c65159SKalle Valo } 2378d5c65159SKalle Valo rx_status->encoding = RX_ENC_HE; 2379d5c65159SKalle Valo rx_status->nss = nss; 23801b8bb94cSWen Gong rx_status->he_gi = ath11k_mac_he_gi_to_nl80211_he_gi(sgi); 238139e81c6aSTamizh chelvam rx_status->bw = ath11k_mac_bw_to_mac80211_bw(bw); 2382d5c65159SKalle Valo break; 2383d5c65159SKalle Valo } 2384d5c65159SKalle Valo } 2385d5c65159SKalle Valo 2386d5c65159SKalle Valo static void ath11k_dp_rx_h_ppdu(struct ath11k *ar, struct hal_rx_desc *rx_desc, 2387d5c65159SKalle Valo struct ieee80211_rx_status *rx_status) 2388d5c65159SKalle Valo { 2389d5c65159SKalle Valo u8 channel_num; 2390e678fbd4SKarthikeyan Periyasamy u32 center_freq, meta_data; 239135970106SCarl Huang struct ieee80211_channel *channel; 2392d5c65159SKalle Valo 2393d5c65159SKalle Valo rx_status->freq = 0; 2394d5c65159SKalle Valo rx_status->rate_idx = 0; 2395d5c65159SKalle Valo rx_status->nss = 0; 2396d5c65159SKalle Valo rx_status->encoding = RX_ENC_LEGACY; 2397d5c65159SKalle Valo rx_status->bw = RATE_INFO_BW_20; 2398d5c65159SKalle Valo 2399d5c65159SKalle Valo rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; 2400d5c65159SKalle Valo 2401e678fbd4SKarthikeyan Periyasamy meta_data = ath11k_dp_rx_h_msdu_start_freq(ar->ab, rx_desc); 2402e678fbd4SKarthikeyan Periyasamy channel_num = meta_data; 2403e678fbd4SKarthikeyan Periyasamy center_freq = meta_data >> 16; 2404d5c65159SKalle Valo 24059d6ae1f5SPradeep Kumar Chitrapu if (center_freq >= ATH11K_MIN_6G_FREQ && 24069d6ae1f5SPradeep Kumar Chitrapu center_freq <= ATH11K_MAX_6G_FREQ) { 24075dcf42f8SPradeep Kumar Chitrapu rx_status->band = NL80211_BAND_6GHZ; 24089d6ae1f5SPradeep Kumar Chitrapu rx_status->freq = center_freq; 24095dcf42f8SPradeep Kumar Chitrapu } else if (channel_num >= 1 && channel_num <= 14) { 2410d5c65159SKalle Valo rx_status->band = NL80211_BAND_2GHZ; 2411*72c8caf9SAditya Kumar Singh } else if (channel_num >= 36 && channel_num <= 177) { 2412d5c65159SKalle Valo rx_status->band = NL80211_BAND_5GHZ; 2413d5c65159SKalle Valo } else { 2414de06b2f7SVenkateswara Naralasetty spin_lock_bh(&ar->data_lock); 241535970106SCarl Huang channel = ar->rx_channel; 241635970106SCarl Huang if (channel) { 241735970106SCarl Huang rx_status->band = channel->band; 2418de06b2f7SVenkateswara Naralasetty channel_num = 241935970106SCarl Huang ieee80211_frequency_to_channel(channel->center_freq); 242035970106SCarl Huang } 2421de06b2f7SVenkateswara Naralasetty spin_unlock_bh(&ar->data_lock); 2422de06b2f7SVenkateswara Naralasetty ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "rx_desc: ", 2423de06b2f7SVenkateswara Naralasetty rx_desc, sizeof(struct hal_rx_desc)); 2424d5c65159SKalle Valo } 2425d5c65159SKalle Valo 24269d6ae1f5SPradeep Kumar Chitrapu if (rx_status->band != NL80211_BAND_6GHZ) 2427d5c65159SKalle Valo rx_status->freq = ieee80211_channel_to_frequency(channel_num, 2428d5c65159SKalle Valo rx_status->band); 2429d5c65159SKalle Valo 2430d5c65159SKalle Valo ath11k_dp_rx_h_rate(ar, rx_desc, rx_status); 2431d5c65159SKalle Valo } 2432d5c65159SKalle Valo 2433d5c65159SKalle Valo static void ath11k_dp_rx_deliver_msdu(struct ath11k *ar, struct napi_struct *napi, 24342167fa60SSriram R struct sk_buff *msdu, 24352167fa60SSriram R struct ieee80211_rx_status *status) 2436d5c65159SKalle Valo { 2437e4eb7b5cSJohn Crispin static const struct ieee80211_radiotap_he known = { 243893634c61SJohn Crispin .data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | 243993634c61SJohn Crispin IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN), 2440e4eb7b5cSJohn Crispin .data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN), 2441e4eb7b5cSJohn Crispin }; 24422167fa60SSriram R struct ieee80211_rx_status *rx_status; 2443e4eb7b5cSJohn Crispin struct ieee80211_radiotap_he *he = NULL; 24442167fa60SSriram R struct ieee80211_sta *pubsta = NULL; 24452167fa60SSriram R struct ath11k_peer *peer; 24462167fa60SSriram R struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 24472167fa60SSriram R u8 decap = DP_RX_DECAP_TYPE_RAW; 24482167fa60SSriram R bool is_mcbc = rxcb->is_mcbc; 24492167fa60SSriram R bool is_eapol = rxcb->is_eapol; 2450d5c65159SKalle Valo 24512167fa60SSriram R if (status->encoding == RX_ENC_HE && 24522167fa60SSriram R !(status->flag & RX_FLAG_RADIOTAP_HE) && 24532167fa60SSriram R !(status->flag & RX_FLAG_SKIP_MONITOR)) { 2454e4eb7b5cSJohn Crispin he = skb_push(msdu, sizeof(known)); 2455e4eb7b5cSJohn Crispin memcpy(he, &known, sizeof(known)); 2456e4eb7b5cSJohn Crispin status->flag |= RX_FLAG_RADIOTAP_HE; 2457e4eb7b5cSJohn Crispin } 2458d5c65159SKalle Valo 24592167fa60SSriram R if (!(status->flag & RX_FLAG_ONLY_MONITOR)) 24602167fa60SSriram R decap = ath11k_dp_rx_h_msdu_start_decap_type(ar->ab, rxcb->rx_desc); 24612167fa60SSriram R 24622167fa60SSriram R spin_lock_bh(&ar->ab->base_lock); 24632167fa60SSriram R peer = ath11k_dp_rx_h_find_peer(ar->ab, msdu); 24642167fa60SSriram R if (peer && peer->sta) 24652167fa60SSriram R pubsta = peer->sta; 24662167fa60SSriram R spin_unlock_bh(&ar->ab->base_lock); 24672167fa60SSriram R 2468d5c65159SKalle Valo ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 2469cf036c41SKalle Valo "rx skb %p len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", 2470d5c65159SKalle Valo msdu, 2471d5c65159SKalle Valo msdu->len, 24722167fa60SSriram R peer ? peer->addr : NULL, 24732167fa60SSriram R rxcb->tid, 24742167fa60SSriram R is_mcbc ? "mcast" : "ucast", 24752167fa60SSriram R rxcb->seq_no, 2476d5c65159SKalle Valo (status->encoding == RX_ENC_LEGACY) ? "legacy" : "", 2477d5c65159SKalle Valo (status->encoding == RX_ENC_HT) ? "ht" : "", 2478d5c65159SKalle Valo (status->encoding == RX_ENC_VHT) ? "vht" : "", 2479d5c65159SKalle Valo (status->encoding == RX_ENC_HE) ? "he" : "", 2480d5c65159SKalle Valo (status->bw == RATE_INFO_BW_40) ? "40" : "", 2481d5c65159SKalle Valo (status->bw == RATE_INFO_BW_80) ? "80" : "", 2482d5c65159SKalle Valo (status->bw == RATE_INFO_BW_160) ? "160" : "", 2483d5c65159SKalle Valo status->enc_flags & RX_ENC_FLAG_SHORT_GI ? "sgi " : "", 2484d5c65159SKalle Valo status->rate_idx, 2485d5c65159SKalle Valo status->nss, 2486d5c65159SKalle Valo status->freq, 2487d5c65159SKalle Valo status->band, status->flag, 2488d5c65159SKalle Valo !!(status->flag & RX_FLAG_FAILED_FCS_CRC), 2489d5c65159SKalle Valo !!(status->flag & RX_FLAG_MMIC_ERROR), 2490d5c65159SKalle Valo !!(status->flag & RX_FLAG_AMSDU_MORE)); 2491d5c65159SKalle Valo 2492aa2092a9SVenkateswara Naralasetty ath11k_dbg_dump(ar->ab, ATH11K_DBG_DP_RX, NULL, "dp rx msdu: ", 2493aa2092a9SVenkateswara Naralasetty msdu->data, msdu->len); 2494aa2092a9SVenkateswara Naralasetty 24952167fa60SSriram R rx_status = IEEE80211_SKB_RXCB(msdu); 24962167fa60SSriram R *rx_status = *status; 24972167fa60SSriram R 2498d5c65159SKalle Valo /* TODO: trace rx packet */ 2499d5c65159SKalle Valo 25002167fa60SSriram R /* PN for multicast packets are not validate in HW, 25012167fa60SSriram R * so skip 802.3 rx path 25023fecca0eSJeff Johnson * Also, fast_rx expects the STA to be authorized, hence 25032167fa60SSriram R * eapol packets are sent in slow path. 25042167fa60SSriram R */ 25052167fa60SSriram R if (decap == DP_RX_DECAP_TYPE_ETHERNET2_DIX && !is_eapol && 25062167fa60SSriram R !(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED)) 25072167fa60SSriram R rx_status->flag |= RX_FLAG_8023; 25082167fa60SSriram R 25092167fa60SSriram R ieee80211_rx_napi(ar->hw, pubsta, msdu, napi); 2510d5c65159SKalle Valo } 2511d5c65159SKalle Valo 2512acc79d98SSriram R static int ath11k_dp_rx_process_msdu(struct ath11k *ar, 2513acc79d98SSriram R struct sk_buff *msdu, 25142167fa60SSriram R struct sk_buff_head *msdu_list, 25152167fa60SSriram R struct ieee80211_rx_status *rx_status) 2516d5c65159SKalle Valo { 2517e678fbd4SKarthikeyan Periyasamy struct ath11k_base *ab = ar->ab; 2518acc79d98SSriram R struct hal_rx_desc *rx_desc, *lrx_desc; 2519e678fbd4SKarthikeyan Periyasamy struct rx_attention *rx_attention; 2520acc79d98SSriram R struct ath11k_skb_rxcb *rxcb; 2521acc79d98SSriram R struct sk_buff *last_buf; 2522acc79d98SSriram R u8 l3_pad_bytes; 2523d7d43782STamizh Chelvam u8 *hdr_status; 2524acc79d98SSriram R u16 msdu_len; 2525acc79d98SSriram R int ret; 2526e678fbd4SKarthikeyan Periyasamy u32 hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz; 2527d5c65159SKalle Valo 2528acc79d98SSriram R last_buf = ath11k_dp_rx_get_msdu_last_buf(msdu_list, msdu); 2529acc79d98SSriram R if (!last_buf) { 2530e678fbd4SKarthikeyan Periyasamy ath11k_warn(ab, 2531acc79d98SSriram R "No valid Rx buffer to access Atten/MSDU_END/MPDU_END tlvs\n"); 2532acc79d98SSriram R ret = -EIO; 2533acc79d98SSriram R goto free_out; 2534d5c65159SKalle Valo } 2535acc79d98SSriram R 2536acc79d98SSriram R rx_desc = (struct hal_rx_desc *)msdu->data; 2537cd18ed4cSBaochen Qiang if (ath11k_dp_rx_h_attn_msdu_len_err(ab, rx_desc)) { 2538cd18ed4cSBaochen Qiang ath11k_warn(ar->ab, "msdu len not valid\n"); 2539cd18ed4cSBaochen Qiang ret = -EIO; 2540cd18ed4cSBaochen Qiang goto free_out; 2541cd18ed4cSBaochen Qiang } 2542cd18ed4cSBaochen Qiang 2543acc79d98SSriram R lrx_desc = (struct hal_rx_desc *)last_buf->data; 2544e678fbd4SKarthikeyan Periyasamy rx_attention = ath11k_dp_rx_get_attention(ab, lrx_desc); 2545e678fbd4SKarthikeyan Periyasamy if (!ath11k_dp_rx_h_attn_msdu_done(rx_attention)) { 2546e678fbd4SKarthikeyan Periyasamy ath11k_warn(ab, "msdu_done bit in attention is not set\n"); 2547acc79d98SSriram R ret = -EIO; 2548acc79d98SSriram R goto free_out; 2549acc79d98SSriram R } 2550acc79d98SSriram R 2551acc79d98SSriram R rxcb = ATH11K_SKB_RXCB(msdu); 2552acc79d98SSriram R rxcb->rx_desc = rx_desc; 2553e678fbd4SKarthikeyan Periyasamy msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(ab, rx_desc); 2554e678fbd4SKarthikeyan Periyasamy l3_pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(ab, lrx_desc); 2555acc79d98SSriram R 2556acc79d98SSriram R if (rxcb->is_frag) { 2557e678fbd4SKarthikeyan Periyasamy skb_pull(msdu, hal_rx_desc_sz); 2558acc79d98SSriram R } else if (!rxcb->is_continuation) { 2559e678fbd4SKarthikeyan Periyasamy if ((msdu_len + hal_rx_desc_sz) > DP_RX_BUFFER_SIZE) { 2560e678fbd4SKarthikeyan Periyasamy hdr_status = ath11k_dp_rx_h_80211_hdr(ab, rx_desc); 2561acc79d98SSriram R ret = -EINVAL; 2562e678fbd4SKarthikeyan Periyasamy ath11k_warn(ab, "invalid msdu len %u\n", msdu_len); 2563e678fbd4SKarthikeyan Periyasamy ath11k_dbg_dump(ab, ATH11K_DBG_DATA, NULL, "", hdr_status, 2564d7d43782STamizh Chelvam sizeof(struct ieee80211_hdr)); 2565e678fbd4SKarthikeyan Periyasamy ath11k_dbg_dump(ab, ATH11K_DBG_DATA, NULL, "", rx_desc, 2566d7d43782STamizh Chelvam sizeof(struct hal_rx_desc)); 2567acc79d98SSriram R goto free_out; 2568acc79d98SSriram R } 2569e678fbd4SKarthikeyan Periyasamy skb_put(msdu, hal_rx_desc_sz + l3_pad_bytes + msdu_len); 2570e678fbd4SKarthikeyan Periyasamy skb_pull(msdu, hal_rx_desc_sz + l3_pad_bytes); 2571acc79d98SSriram R } else { 2572acc79d98SSriram R ret = ath11k_dp_rx_msdu_coalesce(ar, msdu_list, 2573acc79d98SSriram R msdu, last_buf, 2574acc79d98SSriram R l3_pad_bytes, msdu_len); 2575acc79d98SSriram R if (ret) { 2576e678fbd4SKarthikeyan Periyasamy ath11k_warn(ab, 2577acc79d98SSriram R "failed to coalesce msdu rx buffer%d\n", ret); 2578acc79d98SSriram R goto free_out; 2579acc79d98SSriram R } 2580acc79d98SSriram R } 2581acc79d98SSriram R 25822167fa60SSriram R ath11k_dp_rx_h_ppdu(ar, rx_desc, rx_status); 25832167fa60SSriram R ath11k_dp_rx_h_mpdu(ar, msdu, rx_desc, rx_status); 2584acc79d98SSriram R 25852167fa60SSriram R rx_status->flag |= RX_FLAG_SKIP_MONITOR | RX_FLAG_DUP_VALIDATED; 2586acc79d98SSriram R 2587acc79d98SSriram R return 0; 2588acc79d98SSriram R 2589acc79d98SSriram R free_out: 2590acc79d98SSriram R return ret; 2591d5c65159SKalle Valo } 2592d5c65159SKalle Valo 2593acc79d98SSriram R static void ath11k_dp_rx_process_received_packets(struct ath11k_base *ab, 2594d5c65159SKalle Valo struct napi_struct *napi, 2595acc79d98SSriram R struct sk_buff_head *msdu_list, 2596db2ecf9fSP Praneesh int mac_id) 2597d5c65159SKalle Valo { 2598d5c65159SKalle Valo struct sk_buff *msdu; 2599acc79d98SSriram R struct ath11k *ar; 26002167fa60SSriram R struct ieee80211_rx_status rx_status = {0}; 2601acc79d98SSriram R int ret; 2602d5c65159SKalle Valo 2603acc79d98SSriram R if (skb_queue_empty(msdu_list)) 2604d5c65159SKalle Valo return; 2605d5c65159SKalle Valo 260640058803SP Praneesh if (unlikely(!rcu_access_pointer(ab->pdevs_active[mac_id]))) { 2607c4d12cb3SP Praneesh __skb_queue_purge(msdu_list); 2608c4d12cb3SP Praneesh return; 2609acc79d98SSriram R } 2610acc79d98SSriram R 261140058803SP Praneesh ar = ab->pdevs[mac_id].ar; 261240058803SP Praneesh if (unlikely(test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags))) { 2613c4d12cb3SP Praneesh __skb_queue_purge(msdu_list); 2614c4d12cb3SP Praneesh return; 2615acc79d98SSriram R } 2616acc79d98SSriram R 2617c4d12cb3SP Praneesh while ((msdu = __skb_dequeue(msdu_list))) { 26182167fa60SSriram R ret = ath11k_dp_rx_process_msdu(ar, msdu, msdu_list, &rx_status); 261940058803SP Praneesh if (unlikely(ret)) { 2620acc79d98SSriram R ath11k_dbg(ab, ATH11K_DBG_DATA, 2621acc79d98SSriram R "Unable to process msdu %d", ret); 2622d5c65159SKalle Valo dev_kfree_skb_any(msdu); 2623d5c65159SKalle Valo continue; 2624d5c65159SKalle Valo } 2625d5c65159SKalle Valo 26262167fa60SSriram R ath11k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_status); 2627d5c65159SKalle Valo } 2628d5c65159SKalle Valo } 2629d5c65159SKalle Valo 2630acc79d98SSriram R int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, 2631acc79d98SSriram R struct napi_struct *napi, int budget) 2632d5c65159SKalle Valo { 2633acc79d98SSriram R struct ath11k_dp *dp = &ab->dp; 2634acc79d98SSriram R struct dp_rxdma_ring *rx_ring; 2635acc79d98SSriram R int num_buffs_reaped[MAX_RADIOS] = {0}; 2636c4d12cb3SP Praneesh struct sk_buff_head msdu_list[MAX_RADIOS]; 2637acc79d98SSriram R struct ath11k_skb_rxcb *rxcb; 2638acc79d98SSriram R int total_msdu_reaped = 0; 2639d5c65159SKalle Valo struct hal_srng *srng; 2640d5c65159SKalle Valo struct sk_buff *msdu; 2641d5c65159SKalle Valo bool done = false; 2642acc79d98SSriram R int buf_id, mac_id; 2643acc79d98SSriram R struct ath11k *ar; 2644c4d12cb3SP Praneesh struct hal_reo_dest_ring *desc; 2645c4d12cb3SP Praneesh enum hal_reo_dest_ring_push_reason push_reason; 2646c4d12cb3SP Praneesh u32 cookie; 2647acc79d98SSriram R int i; 2648d5c65159SKalle Valo 2649c4d12cb3SP Praneesh for (i = 0; i < MAX_RADIOS; i++) 2650c4d12cb3SP Praneesh __skb_queue_head_init(&msdu_list[i]); 2651d5c65159SKalle Valo 2652acc79d98SSriram R srng = &ab->hal.srng_list[dp->reo_dst_ring[ring_id].ring_id]; 2653d5c65159SKalle Valo 2654d5c65159SKalle Valo spin_lock_bh(&srng->lock); 2655d5c65159SKalle Valo 2656f2180ccbSRameshkumar Sundaram try_again: 2657d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 2658d5c65159SKalle Valo 2659c4d12cb3SP Praneesh while (likely(desc = 2660c4d12cb3SP Praneesh (struct hal_reo_dest_ring *)ath11k_hal_srng_dst_get_next_entry(ab, 2661c4d12cb3SP Praneesh srng))) { 2662293cb583SJohn Crispin cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, 2663c4d12cb3SP Praneesh desc->buf_addr_info.info1); 2664d5c65159SKalle Valo buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, 2665293cb583SJohn Crispin cookie); 2666acc79d98SSriram R mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, cookie); 2667acc79d98SSriram R 2668f9fff67dSNagarajan Maran if (unlikely(buf_id == 0)) 2669f9fff67dSNagarajan Maran continue; 2670f9fff67dSNagarajan Maran 2671acc79d98SSriram R ar = ab->pdevs[mac_id].ar; 2672acc79d98SSriram R rx_ring = &ar->dp.rx_refill_buf_ring; 2673d5c65159SKalle Valo spin_lock_bh(&rx_ring->idr_lock); 2674d5c65159SKalle Valo msdu = idr_find(&rx_ring->bufs_idr, buf_id); 267540058803SP Praneesh if (unlikely(!msdu)) { 2676d5c65159SKalle Valo ath11k_warn(ab, "frame rx with invalid buf_id %d\n", 2677d5c65159SKalle Valo buf_id); 2678d5c65159SKalle Valo spin_unlock_bh(&rx_ring->idr_lock); 2679d5c65159SKalle Valo continue; 2680d5c65159SKalle Valo } 2681d5c65159SKalle Valo 2682d5c65159SKalle Valo idr_remove(&rx_ring->bufs_idr, buf_id); 2683d5c65159SKalle Valo spin_unlock_bh(&rx_ring->idr_lock); 2684d5c65159SKalle Valo 2685d5c65159SKalle Valo rxcb = ATH11K_SKB_RXCB(msdu); 2686d5c65159SKalle Valo dma_unmap_single(ab->dev, rxcb->paddr, 2687d5c65159SKalle Valo msdu->len + skb_tailroom(msdu), 2688d5c65159SKalle Valo DMA_FROM_DEVICE); 2689d5c65159SKalle Valo 2690acc79d98SSriram R num_buffs_reaped[mac_id]++; 2691d5c65159SKalle Valo 2692293cb583SJohn Crispin push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON, 2693c4d12cb3SP Praneesh desc->info0); 269440058803SP Praneesh if (unlikely(push_reason != 269540058803SP Praneesh HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION)) { 2696d5c65159SKalle Valo dev_kfree_skb_any(msdu); 2697acc79d98SSriram R ab->soc_stats.hal_reo_error[dp->reo_dst_ring[ring_id].ring_id]++; 2698d5c65159SKalle Valo continue; 2699d5c65159SKalle Valo } 2700d5c65159SKalle Valo 2701c4d12cb3SP Praneesh rxcb->is_first_msdu = !!(desc->rx_msdu_info.info0 & 2702293cb583SJohn Crispin RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU); 2703c4d12cb3SP Praneesh rxcb->is_last_msdu = !!(desc->rx_msdu_info.info0 & 2704293cb583SJohn Crispin RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU); 2705c4d12cb3SP Praneesh rxcb->is_continuation = !!(desc->rx_msdu_info.info0 & 2706293cb583SJohn Crispin RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); 27072167fa60SSriram R rxcb->peer_id = FIELD_GET(RX_MPDU_DESC_META_DATA_PEER_ID, 2708c4d12cb3SP Praneesh desc->rx_mpdu_info.meta_data); 27092167fa60SSriram R rxcb->seq_no = FIELD_GET(RX_MPDU_DESC_INFO0_SEQ_NUM, 2710c4d12cb3SP Praneesh desc->rx_mpdu_info.info0); 2711acc79d98SSriram R rxcb->tid = FIELD_GET(HAL_REO_DEST_RING_INFO0_RX_QUEUE_NUM, 2712c4d12cb3SP Praneesh desc->info0); 2713acc79d98SSriram R 27142167fa60SSriram R rxcb->mac_id = mac_id; 2715c4d12cb3SP Praneesh __skb_queue_tail(&msdu_list[mac_id], msdu); 2716d5c65159SKalle Valo 2717a1775e73SP Praneesh if (rxcb->is_continuation) { 2718a1775e73SP Praneesh done = false; 2719a1775e73SP Praneesh } else { 2720a1775e73SP Praneesh total_msdu_reaped++; 2721d5c65159SKalle Valo done = true; 2722d5c65159SKalle Valo } 2723a1775e73SP Praneesh 2724a1775e73SP Praneesh if (total_msdu_reaped >= budget) 2725a1775e73SP Praneesh break; 2726d5c65159SKalle Valo } 2727d5c65159SKalle Valo 2728d5c65159SKalle Valo /* Hw might have updated the head pointer after we cached it. 2729d5c65159SKalle Valo * In this case, even though there are entries in the ring we'll 2730d5c65159SKalle Valo * get rx_desc NULL. Give the read another try with updated cached 2731d5c65159SKalle Valo * head pointer so that we can reap complete MPDU in the current 2732d5c65159SKalle Valo * rx processing. 2733d5c65159SKalle Valo */ 273440058803SP Praneesh if (unlikely(!done && ath11k_hal_srng_dst_num_free(ab, srng, true))) { 2735d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 2736d5c65159SKalle Valo goto try_again; 2737d5c65159SKalle Valo } 2738d5c65159SKalle Valo 2739d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 2740d5c65159SKalle Valo 2741d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 2742d5c65159SKalle Valo 274340058803SP Praneesh if (unlikely(!total_msdu_reaped)) 2744d5c65159SKalle Valo goto exit; 2745d5c65159SKalle Valo 2746acc79d98SSriram R for (i = 0; i < ab->num_radios; i++) { 2747acc79d98SSriram R if (!num_buffs_reaped[i]) 2748d5c65159SKalle Valo continue; 2749acc79d98SSriram R 2750db2ecf9fSP Praneesh ath11k_dp_rx_process_received_packets(ab, napi, &msdu_list[i], i); 2751c4d12cb3SP Praneesh 2752acc79d98SSriram R ar = ab->pdevs[i].ar; 2753acc79d98SSriram R rx_ring = &ar->dp.rx_refill_buf_ring; 2754acc79d98SSriram R 2755acc79d98SSriram R ath11k_dp_rxbufs_replenish(ab, i, rx_ring, num_buffs_reaped[i], 2756734223d7SBaochen Qiang ab->hw_params.hal_params->rx_buf_rbm); 2757d5c65159SKalle Valo } 2758d5c65159SKalle Valo exit: 2759db2ecf9fSP Praneesh return total_msdu_reaped; 2760d5c65159SKalle Valo } 2761d5c65159SKalle Valo 2762d5c65159SKalle Valo static void ath11k_dp_rx_update_peer_stats(struct ath11k_sta *arsta, 2763d5c65159SKalle Valo struct hal_rx_mon_ppdu_info *ppdu_info) 2764d5c65159SKalle Valo { 2765d5c65159SKalle Valo struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats; 2766d5c65159SKalle Valo u32 num_msdu; 2767b488c766SWen Gong int i; 2768d5c65159SKalle Valo 2769d5c65159SKalle Valo if (!rx_stats) 2770d5c65159SKalle Valo return; 2771d5c65159SKalle Valo 2772b205ce4cSThiraviyam Mariyappan arsta->rssi_comb = ppdu_info->rssi_comb; 2773b205ce4cSThiraviyam Mariyappan ewma_avg_rssi_add(&arsta->avg_rssi, ppdu_info->rssi_comb); 2774b205ce4cSThiraviyam Mariyappan 2775d5c65159SKalle Valo num_msdu = ppdu_info->tcp_msdu_count + ppdu_info->tcp_ack_msdu_count + 2776d5c65159SKalle Valo ppdu_info->udp_msdu_count + ppdu_info->other_msdu_count; 2777d5c65159SKalle Valo 2778d5c65159SKalle Valo rx_stats->num_msdu += num_msdu; 2779d5c65159SKalle Valo rx_stats->tcp_msdu_count += ppdu_info->tcp_msdu_count + 2780d5c65159SKalle Valo ppdu_info->tcp_ack_msdu_count; 2781d5c65159SKalle Valo rx_stats->udp_msdu_count += ppdu_info->udp_msdu_count; 2782d5c65159SKalle Valo rx_stats->other_msdu_count += ppdu_info->other_msdu_count; 2783d5c65159SKalle Valo 2784d5c65159SKalle Valo if (ppdu_info->preamble_type == HAL_RX_PREAMBLE_11A || 2785d5c65159SKalle Valo ppdu_info->preamble_type == HAL_RX_PREAMBLE_11B) { 2786d5c65159SKalle Valo ppdu_info->nss = 1; 2787d5c65159SKalle Valo ppdu_info->mcs = HAL_RX_MAX_MCS; 2788d5c65159SKalle Valo ppdu_info->tid = IEEE80211_NUM_TIDS; 2789d5c65159SKalle Valo } 2790d5c65159SKalle Valo 2791d5c65159SKalle Valo if (ppdu_info->nss > 0 && ppdu_info->nss <= HAL_RX_MAX_NSS) 2792d5c65159SKalle Valo rx_stats->nss_count[ppdu_info->nss - 1] += num_msdu; 2793d5c65159SKalle Valo 2794d5c65159SKalle Valo if (ppdu_info->mcs <= HAL_RX_MAX_MCS) 2795d5c65159SKalle Valo rx_stats->mcs_count[ppdu_info->mcs] += num_msdu; 2796d5c65159SKalle Valo 2797d5c65159SKalle Valo if (ppdu_info->gi < HAL_RX_GI_MAX) 2798d5c65159SKalle Valo rx_stats->gi_count[ppdu_info->gi] += num_msdu; 2799d5c65159SKalle Valo 2800d5c65159SKalle Valo if (ppdu_info->bw < HAL_RX_BW_MAX) 2801d5c65159SKalle Valo rx_stats->bw_count[ppdu_info->bw] += num_msdu; 2802d5c65159SKalle Valo 2803d5c65159SKalle Valo if (ppdu_info->ldpc < HAL_RX_SU_MU_CODING_MAX) 2804d5c65159SKalle Valo rx_stats->coding_count[ppdu_info->ldpc] += num_msdu; 2805d5c65159SKalle Valo 2806d5c65159SKalle Valo if (ppdu_info->tid <= IEEE80211_NUM_TIDS) 2807d5c65159SKalle Valo rx_stats->tid_count[ppdu_info->tid] += num_msdu; 2808d5c65159SKalle Valo 2809d5c65159SKalle Valo if (ppdu_info->preamble_type < HAL_RX_PREAMBLE_MAX) 2810d5c65159SKalle Valo rx_stats->pream_cnt[ppdu_info->preamble_type] += num_msdu; 2811d5c65159SKalle Valo 2812d5c65159SKalle Valo if (ppdu_info->reception_type < HAL_RX_RECEPTION_TYPE_MAX) 2813d5c65159SKalle Valo rx_stats->reception_type[ppdu_info->reception_type] += num_msdu; 2814d5c65159SKalle Valo 2815d5c65159SKalle Valo if (ppdu_info->is_stbc) 2816d5c65159SKalle Valo rx_stats->stbc_count += num_msdu; 2817d5c65159SKalle Valo 2818d5c65159SKalle Valo if (ppdu_info->beamformed) 2819d5c65159SKalle Valo rx_stats->beamformed_count += num_msdu; 2820d5c65159SKalle Valo 2821d5c65159SKalle Valo if (ppdu_info->num_mpdu_fcs_ok > 1) 2822d5c65159SKalle Valo rx_stats->ampdu_msdu_count += num_msdu; 2823d5c65159SKalle Valo else 2824d5c65159SKalle Valo rx_stats->non_ampdu_msdu_count += num_msdu; 2825d5c65159SKalle Valo 2826d5c65159SKalle Valo rx_stats->num_mpdu_fcs_ok += ppdu_info->num_mpdu_fcs_ok; 2827d5c65159SKalle Valo rx_stats->num_mpdu_fcs_err += ppdu_info->num_mpdu_fcs_err; 28286a0c3702SJohn Crispin rx_stats->dcm_count += ppdu_info->dcm; 28296a0c3702SJohn Crispin rx_stats->ru_alloc_cnt[ppdu_info->ru_alloc] += num_msdu; 2830d5c65159SKalle Valo 2831d5c65159SKalle Valo arsta->rssi_comb = ppdu_info->rssi_comb; 2832b488c766SWen Gong 2833b488c766SWen Gong BUILD_BUG_ON(ARRAY_SIZE(arsta->chain_signal) > 2834b488c766SWen Gong ARRAY_SIZE(ppdu_info->rssi_chain_pri20)); 2835b488c766SWen Gong 2836b488c766SWen Gong for (i = 0; i < ARRAY_SIZE(arsta->chain_signal); i++) 2837b488c766SWen Gong arsta->chain_signal[i] = ppdu_info->rssi_chain_pri20[i]; 2838b488c766SWen Gong 2839d5c65159SKalle Valo rx_stats->rx_duration += ppdu_info->rx_duration; 2840d5c65159SKalle Valo arsta->rx_duration = rx_stats->rx_duration; 2841d5c65159SKalle Valo } 2842d5c65159SKalle Valo 2843d5c65159SKalle Valo static struct sk_buff *ath11k_dp_rx_alloc_mon_status_buf(struct ath11k_base *ab, 2844d5c65159SKalle Valo struct dp_rxdma_ring *rx_ring, 284587e8497aSGovind Singh int *buf_id) 2846d5c65159SKalle Valo { 2847d5c65159SKalle Valo struct sk_buff *skb; 2848d5c65159SKalle Valo dma_addr_t paddr; 2849d5c65159SKalle Valo 2850d5c65159SKalle Valo skb = dev_alloc_skb(DP_RX_BUFFER_SIZE + 2851d5c65159SKalle Valo DP_RX_BUFFER_ALIGN_SIZE); 2852d5c65159SKalle Valo 2853d5c65159SKalle Valo if (!skb) 2854d5c65159SKalle Valo goto fail_alloc_skb; 2855d5c65159SKalle Valo 2856d5c65159SKalle Valo if (!IS_ALIGNED((unsigned long)skb->data, 2857d5c65159SKalle Valo DP_RX_BUFFER_ALIGN_SIZE)) { 2858d5c65159SKalle Valo skb_pull(skb, PTR_ALIGN(skb->data, DP_RX_BUFFER_ALIGN_SIZE) - 2859d5c65159SKalle Valo skb->data); 2860d5c65159SKalle Valo } 2861d5c65159SKalle Valo 2862d5c65159SKalle Valo paddr = dma_map_single(ab->dev, skb->data, 2863d5c65159SKalle Valo skb->len + skb_tailroom(skb), 2864cd6181ffSKalle Valo DMA_FROM_DEVICE); 2865d5c65159SKalle Valo if (unlikely(dma_mapping_error(ab->dev, paddr))) 2866d5c65159SKalle Valo goto fail_free_skb; 2867d5c65159SKalle Valo 2868d5c65159SKalle Valo spin_lock_bh(&rx_ring->idr_lock); 2869d5c65159SKalle Valo *buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 0, 287087e8497aSGovind Singh rx_ring->bufs_max, GFP_ATOMIC); 2871d5c65159SKalle Valo spin_unlock_bh(&rx_ring->idr_lock); 2872d5c65159SKalle Valo if (*buf_id < 0) 2873d5c65159SKalle Valo goto fail_dma_unmap; 2874d5c65159SKalle Valo 2875d5c65159SKalle Valo ATH11K_SKB_RXCB(skb)->paddr = paddr; 2876d5c65159SKalle Valo return skb; 2877d5c65159SKalle Valo 2878d5c65159SKalle Valo fail_dma_unmap: 2879d5c65159SKalle Valo dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb), 2880cd6181ffSKalle Valo DMA_FROM_DEVICE); 2881d5c65159SKalle Valo fail_free_skb: 2882d5c65159SKalle Valo dev_kfree_skb_any(skb); 2883d5c65159SKalle Valo fail_alloc_skb: 2884d5c65159SKalle Valo return NULL; 2885d5c65159SKalle Valo } 2886d5c65159SKalle Valo 2887d5c65159SKalle Valo int ath11k_dp_rx_mon_status_bufs_replenish(struct ath11k_base *ab, int mac_id, 2888d5c65159SKalle Valo struct dp_rxdma_ring *rx_ring, 2889d5c65159SKalle Valo int req_entries, 289087e8497aSGovind Singh enum hal_rx_buf_return_buf_manager mgr) 2891d5c65159SKalle Valo { 2892d5c65159SKalle Valo struct hal_srng *srng; 2893d5c65159SKalle Valo u32 *desc; 2894d5c65159SKalle Valo struct sk_buff *skb; 2895d5c65159SKalle Valo int num_free; 2896d5c65159SKalle Valo int num_remain; 2897d5c65159SKalle Valo int buf_id; 2898d5c65159SKalle Valo u32 cookie; 2899d5c65159SKalle Valo dma_addr_t paddr; 2900d5c65159SKalle Valo 2901d5c65159SKalle Valo req_entries = min(req_entries, rx_ring->bufs_max); 2902d5c65159SKalle Valo 2903d5c65159SKalle Valo srng = &ab->hal.srng_list[rx_ring->refill_buf_ring.ring_id]; 2904d5c65159SKalle Valo 2905d5c65159SKalle Valo spin_lock_bh(&srng->lock); 2906d5c65159SKalle Valo 2907d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 2908d5c65159SKalle Valo 2909d5c65159SKalle Valo num_free = ath11k_hal_srng_src_num_free(ab, srng, true); 2910d5c65159SKalle Valo 2911d5c65159SKalle Valo req_entries = min(num_free, req_entries); 2912d5c65159SKalle Valo num_remain = req_entries; 2913d5c65159SKalle Valo 2914d5c65159SKalle Valo while (num_remain > 0) { 2915d5c65159SKalle Valo skb = ath11k_dp_rx_alloc_mon_status_buf(ab, rx_ring, 291687e8497aSGovind Singh &buf_id); 2917d5c65159SKalle Valo if (!skb) 2918d5c65159SKalle Valo break; 2919d5c65159SKalle Valo paddr = ATH11K_SKB_RXCB(skb)->paddr; 2920d5c65159SKalle Valo 2921d5c65159SKalle Valo desc = ath11k_hal_srng_src_get_next_entry(ab, srng); 2922d5c65159SKalle Valo if (!desc) 2923d5c65159SKalle Valo goto fail_desc_get; 2924d5c65159SKalle Valo 2925d5c65159SKalle Valo cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, mac_id) | 2926d5c65159SKalle Valo FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id); 2927d5c65159SKalle Valo 2928d5c65159SKalle Valo num_remain--; 2929d5c65159SKalle Valo 2930d5c65159SKalle Valo ath11k_hal_rx_buf_addr_info_set(desc, paddr, cookie, mgr); 2931d5c65159SKalle Valo } 2932d5c65159SKalle Valo 2933d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 2934d5c65159SKalle Valo 2935d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 2936d5c65159SKalle Valo 2937d5c65159SKalle Valo return req_entries - num_remain; 2938d5c65159SKalle Valo 2939d5c65159SKalle Valo fail_desc_get: 2940d5c65159SKalle Valo spin_lock_bh(&rx_ring->idr_lock); 2941d5c65159SKalle Valo idr_remove(&rx_ring->bufs_idr, buf_id); 2942d5c65159SKalle Valo spin_unlock_bh(&rx_ring->idr_lock); 2943d5c65159SKalle Valo dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb), 2944cd6181ffSKalle Valo DMA_FROM_DEVICE); 2945d5c65159SKalle Valo dev_kfree_skb_any(skb); 2946d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 2947d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 2948d5c65159SKalle Valo 2949d5c65159SKalle Valo return req_entries - num_remain; 2950d5c65159SKalle Valo } 2951d5c65159SKalle Valo 29527e2ea2e9SAnilkumar Kolli #define ATH11K_DP_RX_FULL_MON_PPDU_ID_WRAP 32535 29537e2ea2e9SAnilkumar Kolli 29547e2ea2e9SAnilkumar Kolli static void 29557e2ea2e9SAnilkumar Kolli ath11k_dp_rx_mon_update_status_buf_state(struct ath11k_mon_data *pmon, 29567e2ea2e9SAnilkumar Kolli struct hal_tlv_hdr *tlv) 29577e2ea2e9SAnilkumar Kolli { 29587e2ea2e9SAnilkumar Kolli struct hal_rx_ppdu_start *ppdu_start; 29597e2ea2e9SAnilkumar Kolli u16 ppdu_id_diff, ppdu_id, tlv_len; 29607e2ea2e9SAnilkumar Kolli u8 *ptr; 29617e2ea2e9SAnilkumar Kolli 29627e2ea2e9SAnilkumar Kolli /* PPDU id is part of second tlv, move ptr to second tlv */ 29637e2ea2e9SAnilkumar Kolli tlv_len = FIELD_GET(HAL_TLV_HDR_LEN, tlv->tl); 29647e2ea2e9SAnilkumar Kolli ptr = (u8 *)tlv; 29657e2ea2e9SAnilkumar Kolli ptr += sizeof(*tlv) + tlv_len; 29667e2ea2e9SAnilkumar Kolli tlv = (struct hal_tlv_hdr *)ptr; 29677e2ea2e9SAnilkumar Kolli 29687e2ea2e9SAnilkumar Kolli if (FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl) != HAL_RX_PPDU_START) 29697e2ea2e9SAnilkumar Kolli return; 29707e2ea2e9SAnilkumar Kolli 29717e2ea2e9SAnilkumar Kolli ptr += sizeof(*tlv); 29727e2ea2e9SAnilkumar Kolli ppdu_start = (struct hal_rx_ppdu_start *)ptr; 29737e2ea2e9SAnilkumar Kolli ppdu_id = FIELD_GET(HAL_RX_PPDU_START_INFO0_PPDU_ID, 29747e2ea2e9SAnilkumar Kolli __le32_to_cpu(ppdu_start->info0)); 29757e2ea2e9SAnilkumar Kolli 29767e2ea2e9SAnilkumar Kolli if (pmon->sw_mon_entries.ppdu_id < ppdu_id) { 29777e2ea2e9SAnilkumar Kolli pmon->buf_state = DP_MON_STATUS_LEAD; 29787e2ea2e9SAnilkumar Kolli ppdu_id_diff = ppdu_id - pmon->sw_mon_entries.ppdu_id; 29797e2ea2e9SAnilkumar Kolli if (ppdu_id_diff > ATH11K_DP_RX_FULL_MON_PPDU_ID_WRAP) 29807e2ea2e9SAnilkumar Kolli pmon->buf_state = DP_MON_STATUS_LAG; 29817e2ea2e9SAnilkumar Kolli } else if (pmon->sw_mon_entries.ppdu_id > ppdu_id) { 29827e2ea2e9SAnilkumar Kolli pmon->buf_state = DP_MON_STATUS_LAG; 29837e2ea2e9SAnilkumar Kolli ppdu_id_diff = pmon->sw_mon_entries.ppdu_id - ppdu_id; 29847e2ea2e9SAnilkumar Kolli if (ppdu_id_diff > ATH11K_DP_RX_FULL_MON_PPDU_ID_WRAP) 29857e2ea2e9SAnilkumar Kolli pmon->buf_state = DP_MON_STATUS_LEAD; 29867e2ea2e9SAnilkumar Kolli } 29877e2ea2e9SAnilkumar Kolli } 29887e2ea2e9SAnilkumar Kolli 2989d5c65159SKalle Valo static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, 2990d5c65159SKalle Valo int *budget, struct sk_buff_head *skb_list) 2991d5c65159SKalle Valo { 29924152e420SCarl Huang struct ath11k *ar; 2993734223d7SBaochen Qiang const struct ath11k_hw_hal_params *hal_params; 29944152e420SCarl Huang struct ath11k_pdev_dp *dp; 29954152e420SCarl Huang struct dp_rxdma_ring *rx_ring; 29967e2ea2e9SAnilkumar Kolli struct ath11k_mon_data *pmon; 2997d5c65159SKalle Valo struct hal_srng *srng; 2998d5c65159SKalle Valo void *rx_mon_status_desc; 2999d5c65159SKalle Valo struct sk_buff *skb; 3000d5c65159SKalle Valo struct ath11k_skb_rxcb *rxcb; 3001d5c65159SKalle Valo struct hal_tlv_hdr *tlv; 3002d5c65159SKalle Valo u32 cookie; 30034152e420SCarl Huang int buf_id, srng_id; 3004d5c65159SKalle Valo dma_addr_t paddr; 3005d5c65159SKalle Valo u8 rbm; 3006d5c65159SKalle Valo int num_buffs_reaped = 0; 3007d5c65159SKalle Valo 30084152e420SCarl Huang ar = ab->pdevs[ath11k_hw_mac_id_to_pdev_id(&ab->hw_params, mac_id)].ar; 30094152e420SCarl Huang dp = &ar->dp; 30107e2ea2e9SAnilkumar Kolli pmon = &dp->mon_data; 30114152e420SCarl Huang srng_id = ath11k_hw_mac_id_to_srng_id(&ab->hw_params, mac_id); 30124152e420SCarl Huang rx_ring = &dp->rx_mon_status_refill_ring[srng_id]; 30134152e420SCarl Huang 3014d5c65159SKalle Valo srng = &ab->hal.srng_list[rx_ring->refill_buf_ring.ring_id]; 3015d5c65159SKalle Valo 3016d5c65159SKalle Valo spin_lock_bh(&srng->lock); 3017d5c65159SKalle Valo 3018d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 3019d5c65159SKalle Valo while (*budget) { 3020d5c65159SKalle Valo *budget -= 1; 3021d5c65159SKalle Valo rx_mon_status_desc = 3022d5c65159SKalle Valo ath11k_hal_srng_src_peek(ab, srng); 30237e2ea2e9SAnilkumar Kolli if (!rx_mon_status_desc) { 30247e2ea2e9SAnilkumar Kolli pmon->buf_state = DP_MON_STATUS_REPLINISH; 3025d5c65159SKalle Valo break; 30267e2ea2e9SAnilkumar Kolli } 3027d5c65159SKalle Valo 3028d5c65159SKalle Valo ath11k_hal_rx_buf_addr_info_get(rx_mon_status_desc, &paddr, 3029d5c65159SKalle Valo &cookie, &rbm); 3030d5c65159SKalle Valo if (paddr) { 3031d5c65159SKalle Valo buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, cookie); 3032d5c65159SKalle Valo 3033d5c65159SKalle Valo spin_lock_bh(&rx_ring->idr_lock); 3034d5c65159SKalle Valo skb = idr_find(&rx_ring->bufs_idr, buf_id); 303568e93ac5SHarshitha Prem spin_unlock_bh(&rx_ring->idr_lock); 303668e93ac5SHarshitha Prem 3037d5c65159SKalle Valo if (!skb) { 3038d5c65159SKalle Valo ath11k_warn(ab, "rx monitor status with invalid buf_id %d\n", 3039d5c65159SKalle Valo buf_id); 30407e2ea2e9SAnilkumar Kolli pmon->buf_state = DP_MON_STATUS_REPLINISH; 304132a2be49SMiles Hu goto move_next; 3042d5c65159SKalle Valo } 3043d5c65159SKalle Valo 3044d5c65159SKalle Valo rxcb = ATH11K_SKB_RXCB(skb); 3045d5c65159SKalle Valo 304668e93ac5SHarshitha Prem dma_sync_single_for_cpu(ab->dev, rxcb->paddr, 3047d5c65159SKalle Valo skb->len + skb_tailroom(skb), 3048cd6181ffSKalle Valo DMA_FROM_DEVICE); 3049d5c65159SKalle Valo 3050d5c65159SKalle Valo tlv = (struct hal_tlv_hdr *)skb->data; 3051d5c65159SKalle Valo if (FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl) != 3052d5c65159SKalle Valo HAL_RX_STATUS_BUFFER_DONE) { 305368e93ac5SHarshitha Prem ath11k_warn(ab, "mon status DONE not set %lx, buf_id %d\n", 305432a2be49SMiles Hu FIELD_GET(HAL_TLV_HDR_TAG, 305568e93ac5SHarshitha Prem tlv->tl), buf_id); 305668e93ac5SHarshitha Prem /* If done status is missing, hold onto status 305768e93ac5SHarshitha Prem * ring until status is done for this status 305868e93ac5SHarshitha Prem * ring buffer. 305968e93ac5SHarshitha Prem * Keep HP in mon_status_ring unchanged, 306068e93ac5SHarshitha Prem * and break from here. 306168e93ac5SHarshitha Prem * Check status for same buffer for next time 306268e93ac5SHarshitha Prem */ 30637e2ea2e9SAnilkumar Kolli pmon->buf_state = DP_MON_STATUS_NO_DMA; 306468e93ac5SHarshitha Prem break; 3065d5c65159SKalle Valo } 3066d5c65159SKalle Valo 306768e93ac5SHarshitha Prem spin_lock_bh(&rx_ring->idr_lock); 306868e93ac5SHarshitha Prem idr_remove(&rx_ring->bufs_idr, buf_id); 306968e93ac5SHarshitha Prem spin_unlock_bh(&rx_ring->idr_lock); 30707e2ea2e9SAnilkumar Kolli if (ab->hw_params.full_monitor_mode) { 30717e2ea2e9SAnilkumar Kolli ath11k_dp_rx_mon_update_status_buf_state(pmon, tlv); 30727e2ea2e9SAnilkumar Kolli if (paddr == pmon->mon_status_paddr) 30737e2ea2e9SAnilkumar Kolli pmon->buf_state = DP_MON_STATUS_MATCH; 30747e2ea2e9SAnilkumar Kolli } 307568e93ac5SHarshitha Prem 307668e93ac5SHarshitha Prem dma_unmap_single(ab->dev, rxcb->paddr, 307768e93ac5SHarshitha Prem skb->len + skb_tailroom(skb), 307868e93ac5SHarshitha Prem DMA_FROM_DEVICE); 307968e93ac5SHarshitha Prem 3080d5c65159SKalle Valo __skb_queue_tail(skb_list, skb); 30817e2ea2e9SAnilkumar Kolli } else { 30827e2ea2e9SAnilkumar Kolli pmon->buf_state = DP_MON_STATUS_REPLINISH; 3083d5c65159SKalle Valo } 308432a2be49SMiles Hu move_next: 3085d5c65159SKalle Valo skb = ath11k_dp_rx_alloc_mon_status_buf(ab, rx_ring, 308687e8497aSGovind Singh &buf_id); 3087d5c65159SKalle Valo 3088d5c65159SKalle Valo if (!skb) { 3089734223d7SBaochen Qiang hal_params = ab->hw_params.hal_params; 3090d5c65159SKalle Valo ath11k_hal_rx_buf_addr_info_set(rx_mon_status_desc, 0, 0, 3091734223d7SBaochen Qiang hal_params->rx_buf_rbm); 3092d5c65159SKalle Valo num_buffs_reaped++; 3093d5c65159SKalle Valo break; 3094d5c65159SKalle Valo } 3095d5c65159SKalle Valo rxcb = ATH11K_SKB_RXCB(skb); 3096d5c65159SKalle Valo 3097d5c65159SKalle Valo cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, mac_id) | 3098d5c65159SKalle Valo FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id); 3099d5c65159SKalle Valo 3100d5c65159SKalle Valo ath11k_hal_rx_buf_addr_info_set(rx_mon_status_desc, rxcb->paddr, 3101734223d7SBaochen Qiang cookie, 3102734223d7SBaochen Qiang ab->hw_params.hal_params->rx_buf_rbm); 3103d5c65159SKalle Valo ath11k_hal_srng_src_get_next_entry(ab, srng); 3104d5c65159SKalle Valo num_buffs_reaped++; 3105d5c65159SKalle Valo } 3106d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 3107d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 3108d5c65159SKalle Valo 3109d5c65159SKalle Valo return num_buffs_reaped; 3110d5c65159SKalle Valo } 3111d5c65159SKalle Valo 3112243874c6SManikanta Pubbisetty static void ath11k_dp_rx_frag_timer(struct timer_list *timer) 3113d5c65159SKalle Valo { 3114243874c6SManikanta Pubbisetty struct dp_rx_tid *rx_tid = from_timer(rx_tid, timer, frag_timer); 3115d5c65159SKalle Valo 3116243874c6SManikanta Pubbisetty spin_lock_bh(&rx_tid->ab->base_lock); 3117243874c6SManikanta Pubbisetty if (rx_tid->last_frag_no && 3118243874c6SManikanta Pubbisetty rx_tid->rx_frag_bitmap == GENMASK(rx_tid->last_frag_no, 0)) { 3119243874c6SManikanta Pubbisetty spin_unlock_bh(&rx_tid->ab->base_lock); 3120243874c6SManikanta Pubbisetty return; 3121243874c6SManikanta Pubbisetty } 3122243874c6SManikanta Pubbisetty ath11k_dp_rx_frags_cleanup(rx_tid, true); 3123243874c6SManikanta Pubbisetty spin_unlock_bh(&rx_tid->ab->base_lock); 3124d5c65159SKalle Valo } 3125d5c65159SKalle Valo 3126243874c6SManikanta Pubbisetty int ath11k_peer_rx_frag_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id) 3127243874c6SManikanta Pubbisetty { 3128243874c6SManikanta Pubbisetty struct ath11k_base *ab = ar->ab; 3129243874c6SManikanta Pubbisetty struct crypto_shash *tfm; 3130243874c6SManikanta Pubbisetty struct ath11k_peer *peer; 3131243874c6SManikanta Pubbisetty struct dp_rx_tid *rx_tid; 3132243874c6SManikanta Pubbisetty int i; 3133d5c65159SKalle Valo 3134243874c6SManikanta Pubbisetty tfm = crypto_alloc_shash("michael_mic", 0, 0); 3135a87a9110SKalle Valo if (IS_ERR(tfm)) { 3136a87a9110SKalle Valo ath11k_warn(ab, "failed to allocate michael_mic shash: %ld\n", 3137a87a9110SKalle Valo PTR_ERR(tfm)); 3138243874c6SManikanta Pubbisetty return PTR_ERR(tfm); 3139a87a9110SKalle Valo } 3140d5c65159SKalle Valo 3141243874c6SManikanta Pubbisetty spin_lock_bh(&ab->base_lock); 3142d5c65159SKalle Valo 3143243874c6SManikanta Pubbisetty peer = ath11k_peer_find(ab, vdev_id, peer_mac); 3144243874c6SManikanta Pubbisetty if (!peer) { 3145243874c6SManikanta Pubbisetty ath11k_warn(ab, "failed to find the peer to set up fragment info\n"); 3146243874c6SManikanta Pubbisetty spin_unlock_bh(&ab->base_lock); 3147ed3f83b3SMiaoqian Lin crypto_free_shash(tfm); 3148243874c6SManikanta Pubbisetty return -ENOENT; 3149243874c6SManikanta Pubbisetty } 3150243874c6SManikanta Pubbisetty 3151243874c6SManikanta Pubbisetty for (i = 0; i <= IEEE80211_NUM_TIDS; i++) { 3152243874c6SManikanta Pubbisetty rx_tid = &peer->rx_tid[i]; 3153243874c6SManikanta Pubbisetty rx_tid->ab = ab; 3154243874c6SManikanta Pubbisetty timer_setup(&rx_tid->frag_timer, ath11k_dp_rx_frag_timer, 0); 3155243874c6SManikanta Pubbisetty skb_queue_head_init(&rx_tid->rx_frags); 3156243874c6SManikanta Pubbisetty } 3157243874c6SManikanta Pubbisetty 3158243874c6SManikanta Pubbisetty peer->tfm_mmic = tfm; 3159a06bfb3cSHarshitha Prem peer->dp_setup_done = true; 3160243874c6SManikanta Pubbisetty spin_unlock_bh(&ab->base_lock); 3161243874c6SManikanta Pubbisetty 3162243874c6SManikanta Pubbisetty return 0; 3163243874c6SManikanta Pubbisetty } 3164243874c6SManikanta Pubbisetty 3165243874c6SManikanta Pubbisetty static int ath11k_dp_rx_h_michael_mic(struct crypto_shash *tfm, u8 *key, 3166243874c6SManikanta Pubbisetty struct ieee80211_hdr *hdr, u8 *data, 3167243874c6SManikanta Pubbisetty size_t data_len, u8 *mic) 3168243874c6SManikanta Pubbisetty { 3169243874c6SManikanta Pubbisetty SHASH_DESC_ON_STACK(desc, tfm); 3170243874c6SManikanta Pubbisetty u8 mic_hdr[16] = {0}; 3171243874c6SManikanta Pubbisetty u8 tid = 0; 3172243874c6SManikanta Pubbisetty int ret; 3173243874c6SManikanta Pubbisetty 3174243874c6SManikanta Pubbisetty if (!tfm) 3175243874c6SManikanta Pubbisetty return -EINVAL; 3176243874c6SManikanta Pubbisetty 3177243874c6SManikanta Pubbisetty desc->tfm = tfm; 3178243874c6SManikanta Pubbisetty 3179243874c6SManikanta Pubbisetty ret = crypto_shash_setkey(tfm, key, 8); 3180243874c6SManikanta Pubbisetty if (ret) 3181243874c6SManikanta Pubbisetty goto out; 3182243874c6SManikanta Pubbisetty 3183243874c6SManikanta Pubbisetty ret = crypto_shash_init(desc); 3184243874c6SManikanta Pubbisetty if (ret) 3185243874c6SManikanta Pubbisetty goto out; 3186243874c6SManikanta Pubbisetty 3187243874c6SManikanta Pubbisetty /* TKIP MIC header */ 3188243874c6SManikanta Pubbisetty memcpy(mic_hdr, ieee80211_get_DA(hdr), ETH_ALEN); 3189243874c6SManikanta Pubbisetty memcpy(mic_hdr + ETH_ALEN, ieee80211_get_SA(hdr), ETH_ALEN); 3190243874c6SManikanta Pubbisetty if (ieee80211_is_data_qos(hdr->frame_control)) 3191243874c6SManikanta Pubbisetty tid = ieee80211_get_tid(hdr); 3192243874c6SManikanta Pubbisetty mic_hdr[12] = tid; 3193243874c6SManikanta Pubbisetty 3194243874c6SManikanta Pubbisetty ret = crypto_shash_update(desc, mic_hdr, 16); 3195243874c6SManikanta Pubbisetty if (ret) 3196243874c6SManikanta Pubbisetty goto out; 3197243874c6SManikanta Pubbisetty ret = crypto_shash_update(desc, data, data_len); 3198243874c6SManikanta Pubbisetty if (ret) 3199243874c6SManikanta Pubbisetty goto out; 3200243874c6SManikanta Pubbisetty ret = crypto_shash_final(desc, mic); 3201243874c6SManikanta Pubbisetty out: 3202243874c6SManikanta Pubbisetty shash_desc_zero(desc); 3203d5c65159SKalle Valo return ret; 3204d5c65159SKalle Valo } 3205d5c65159SKalle Valo 3206243874c6SManikanta Pubbisetty static int ath11k_dp_rx_h_verify_tkip_mic(struct ath11k *ar, struct ath11k_peer *peer, 3207243874c6SManikanta Pubbisetty struct sk_buff *msdu) 3208d5c65159SKalle Valo { 3209243874c6SManikanta Pubbisetty struct hal_rx_desc *rx_desc = (struct hal_rx_desc *)msdu->data; 3210243874c6SManikanta Pubbisetty struct ieee80211_rx_status *rxs = IEEE80211_SKB_RXCB(msdu); 3211243874c6SManikanta Pubbisetty struct ieee80211_key_conf *key_conf; 3212243874c6SManikanta Pubbisetty struct ieee80211_hdr *hdr; 3213243874c6SManikanta Pubbisetty u8 mic[IEEE80211_CCMP_MIC_LEN]; 3214243874c6SManikanta Pubbisetty int head_len, tail_len, ret; 3215243874c6SManikanta Pubbisetty size_t data_len; 3216e678fbd4SKarthikeyan Periyasamy u32 hdr_len, hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz; 3217243874c6SManikanta Pubbisetty u8 *key, *data; 3218243874c6SManikanta Pubbisetty u8 key_idx; 3219d5c65159SKalle Valo 3220e678fbd4SKarthikeyan Periyasamy if (ath11k_dp_rx_h_mpdu_start_enctype(ar->ab, rx_desc) != 3221e678fbd4SKarthikeyan Periyasamy HAL_ENCRYPT_TYPE_TKIP_MIC) 3222243874c6SManikanta Pubbisetty return 0; 3223d5c65159SKalle Valo 3224e678fbd4SKarthikeyan Periyasamy hdr = (struct ieee80211_hdr *)(msdu->data + hal_rx_desc_sz); 3225243874c6SManikanta Pubbisetty hdr_len = ieee80211_hdrlen(hdr->frame_control); 3226e678fbd4SKarthikeyan Periyasamy head_len = hdr_len + hal_rx_desc_sz + IEEE80211_TKIP_IV_LEN; 3227243874c6SManikanta Pubbisetty tail_len = IEEE80211_CCMP_MIC_LEN + IEEE80211_TKIP_ICV_LEN + FCS_LEN; 3228d5c65159SKalle Valo 3229243874c6SManikanta Pubbisetty if (!is_multicast_ether_addr(hdr->addr1)) 3230243874c6SManikanta Pubbisetty key_idx = peer->ucast_keyidx; 3231243874c6SManikanta Pubbisetty else 3232243874c6SManikanta Pubbisetty key_idx = peer->mcast_keyidx; 3233d5c65159SKalle Valo 3234243874c6SManikanta Pubbisetty key_conf = peer->keys[key_idx]; 3235d5c65159SKalle Valo 3236243874c6SManikanta Pubbisetty data = msdu->data + head_len; 3237243874c6SManikanta Pubbisetty data_len = msdu->len - head_len - tail_len; 3238243874c6SManikanta Pubbisetty key = &key_conf->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]; 3239d5c65159SKalle Valo 3240243874c6SManikanta Pubbisetty ret = ath11k_dp_rx_h_michael_mic(peer->tfm_mmic, key, hdr, data, data_len, mic); 3241243874c6SManikanta Pubbisetty if (ret || memcmp(mic, data + data_len, IEEE80211_CCMP_MIC_LEN)) 3242243874c6SManikanta Pubbisetty goto mic_fail; 3243d5c65159SKalle Valo 3244243874c6SManikanta Pubbisetty return 0; 3245243874c6SManikanta Pubbisetty 3246243874c6SManikanta Pubbisetty mic_fail: 3247b7b527b9SJason Yan (ATH11K_SKB_RXCB(msdu))->is_first_msdu = true; 3248b7b527b9SJason Yan (ATH11K_SKB_RXCB(msdu))->is_last_msdu = true; 3249243874c6SManikanta Pubbisetty 3250243874c6SManikanta Pubbisetty rxs->flag |= RX_FLAG_MMIC_ERROR | RX_FLAG_MMIC_STRIPPED | 3251243874c6SManikanta Pubbisetty RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED; 3252e678fbd4SKarthikeyan Periyasamy skb_pull(msdu, hal_rx_desc_sz); 3253243874c6SManikanta Pubbisetty 3254243874c6SManikanta Pubbisetty ath11k_dp_rx_h_ppdu(ar, rx_desc, rxs); 3255243874c6SManikanta Pubbisetty ath11k_dp_rx_h_undecap(ar, msdu, rx_desc, 3256243874c6SManikanta Pubbisetty HAL_ENCRYPT_TYPE_TKIP_MIC, rxs, true); 3257243874c6SManikanta Pubbisetty ieee80211_rx(ar->hw, msdu); 3258243874c6SManikanta Pubbisetty return -EINVAL; 3259d5c65159SKalle Valo } 3260d5c65159SKalle Valo 3261243874c6SManikanta Pubbisetty static void ath11k_dp_rx_h_undecap_frag(struct ath11k *ar, struct sk_buff *msdu, 3262243874c6SManikanta Pubbisetty enum hal_encrypt_type enctype, u32 flags) 3263243874c6SManikanta Pubbisetty { 3264243874c6SManikanta Pubbisetty struct ieee80211_hdr *hdr; 3265243874c6SManikanta Pubbisetty size_t hdr_len; 3266243874c6SManikanta Pubbisetty size_t crypto_len; 3267e678fbd4SKarthikeyan Periyasamy u32 hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz; 3268d5c65159SKalle Valo 3269243874c6SManikanta Pubbisetty if (!flags) 3270243874c6SManikanta Pubbisetty return; 3271d5c65159SKalle Valo 3272e678fbd4SKarthikeyan Periyasamy hdr = (struct ieee80211_hdr *)(msdu->data + hal_rx_desc_sz); 3273243874c6SManikanta Pubbisetty 3274243874c6SManikanta Pubbisetty if (flags & RX_FLAG_MIC_STRIPPED) 3275d5c65159SKalle Valo skb_trim(msdu, msdu->len - 3276d5c65159SKalle Valo ath11k_dp_rx_crypto_mic_len(ar, enctype)); 3277243874c6SManikanta Pubbisetty 3278243874c6SManikanta Pubbisetty if (flags & RX_FLAG_ICV_STRIPPED) 3279243874c6SManikanta Pubbisetty skb_trim(msdu, msdu->len - 3280243874c6SManikanta Pubbisetty ath11k_dp_rx_crypto_icv_len(ar, enctype)); 3281243874c6SManikanta Pubbisetty 3282243874c6SManikanta Pubbisetty if (flags & RX_FLAG_IV_STRIPPED) { 3283243874c6SManikanta Pubbisetty hdr_len = ieee80211_hdrlen(hdr->frame_control); 3284243874c6SManikanta Pubbisetty crypto_len = ath11k_dp_rx_crypto_param_len(ar, enctype); 3285243874c6SManikanta Pubbisetty 3286e678fbd4SKarthikeyan Periyasamy memmove((void *)msdu->data + hal_rx_desc_sz + crypto_len, 3287e678fbd4SKarthikeyan Periyasamy (void *)msdu->data + hal_rx_desc_sz, hdr_len); 3288243874c6SManikanta Pubbisetty skb_pull(msdu, crypto_len); 3289d5c65159SKalle Valo } 3290d5c65159SKalle Valo } 3291d5c65159SKalle Valo 3292243874c6SManikanta Pubbisetty static int ath11k_dp_rx_h_defrag(struct ath11k *ar, 3293243874c6SManikanta Pubbisetty struct ath11k_peer *peer, 3294243874c6SManikanta Pubbisetty struct dp_rx_tid *rx_tid, 3295243874c6SManikanta Pubbisetty struct sk_buff **defrag_skb) 3296243874c6SManikanta Pubbisetty { 3297243874c6SManikanta Pubbisetty struct hal_rx_desc *rx_desc; 3298243874c6SManikanta Pubbisetty struct sk_buff *skb, *first_frag, *last_frag; 3299243874c6SManikanta Pubbisetty struct ieee80211_hdr *hdr; 3300e678fbd4SKarthikeyan Periyasamy struct rx_attention *rx_attention; 3301243874c6SManikanta Pubbisetty enum hal_encrypt_type enctype; 3302243874c6SManikanta Pubbisetty bool is_decrypted = false; 3303243874c6SManikanta Pubbisetty int msdu_len = 0; 3304243874c6SManikanta Pubbisetty int extra_space; 3305e678fbd4SKarthikeyan Periyasamy u32 flags, hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz; 3306243874c6SManikanta Pubbisetty 3307243874c6SManikanta Pubbisetty first_frag = skb_peek(&rx_tid->rx_frags); 3308243874c6SManikanta Pubbisetty last_frag = skb_peek_tail(&rx_tid->rx_frags); 3309243874c6SManikanta Pubbisetty 3310243874c6SManikanta Pubbisetty skb_queue_walk(&rx_tid->rx_frags, skb) { 3311243874c6SManikanta Pubbisetty flags = 0; 3312243874c6SManikanta Pubbisetty rx_desc = (struct hal_rx_desc *)skb->data; 3313e678fbd4SKarthikeyan Periyasamy hdr = (struct ieee80211_hdr *)(skb->data + hal_rx_desc_sz); 3314243874c6SManikanta Pubbisetty 3315e678fbd4SKarthikeyan Periyasamy enctype = ath11k_dp_rx_h_mpdu_start_enctype(ar->ab, rx_desc); 3316e678fbd4SKarthikeyan Periyasamy if (enctype != HAL_ENCRYPT_TYPE_OPEN) { 3317e678fbd4SKarthikeyan Periyasamy rx_attention = ath11k_dp_rx_get_attention(ar->ab, rx_desc); 3318e678fbd4SKarthikeyan Periyasamy is_decrypted = ath11k_dp_rx_h_attn_is_decrypted(rx_attention); 3319e678fbd4SKarthikeyan Periyasamy } 3320243874c6SManikanta Pubbisetty 3321243874c6SManikanta Pubbisetty if (is_decrypted) { 3322243874c6SManikanta Pubbisetty if (skb != first_frag) 3323243874c6SManikanta Pubbisetty flags |= RX_FLAG_IV_STRIPPED; 3324243874c6SManikanta Pubbisetty if (skb != last_frag) 3325243874c6SManikanta Pubbisetty flags |= RX_FLAG_ICV_STRIPPED | 3326243874c6SManikanta Pubbisetty RX_FLAG_MIC_STRIPPED; 3327243874c6SManikanta Pubbisetty } 3328243874c6SManikanta Pubbisetty 3329243874c6SManikanta Pubbisetty /* RX fragments are always raw packets */ 3330243874c6SManikanta Pubbisetty if (skb != last_frag) 3331243874c6SManikanta Pubbisetty skb_trim(skb, skb->len - FCS_LEN); 3332243874c6SManikanta Pubbisetty ath11k_dp_rx_h_undecap_frag(ar, skb, enctype, flags); 3333243874c6SManikanta Pubbisetty 3334243874c6SManikanta Pubbisetty if (skb != first_frag) 3335e678fbd4SKarthikeyan Periyasamy skb_pull(skb, hal_rx_desc_sz + 3336243874c6SManikanta Pubbisetty ieee80211_hdrlen(hdr->frame_control)); 3337243874c6SManikanta Pubbisetty msdu_len += skb->len; 3338243874c6SManikanta Pubbisetty } 3339243874c6SManikanta Pubbisetty 3340243874c6SManikanta Pubbisetty extra_space = msdu_len - (DP_RX_BUFFER_SIZE + skb_tailroom(first_frag)); 3341243874c6SManikanta Pubbisetty if (extra_space > 0 && 3342243874c6SManikanta Pubbisetty (pskb_expand_head(first_frag, 0, extra_space, GFP_ATOMIC) < 0)) 3343243874c6SManikanta Pubbisetty return -ENOMEM; 3344243874c6SManikanta Pubbisetty 3345243874c6SManikanta Pubbisetty __skb_unlink(first_frag, &rx_tid->rx_frags); 3346243874c6SManikanta Pubbisetty while ((skb = __skb_dequeue(&rx_tid->rx_frags))) { 3347243874c6SManikanta Pubbisetty skb_put_data(first_frag, skb->data, skb->len); 3348243874c6SManikanta Pubbisetty dev_kfree_skb_any(skb); 3349243874c6SManikanta Pubbisetty } 3350243874c6SManikanta Pubbisetty 3351e678fbd4SKarthikeyan Periyasamy hdr = (struct ieee80211_hdr *)(first_frag->data + hal_rx_desc_sz); 3352243874c6SManikanta Pubbisetty hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); 3353243874c6SManikanta Pubbisetty ATH11K_SKB_RXCB(first_frag)->is_frag = 1; 3354243874c6SManikanta Pubbisetty 3355243874c6SManikanta Pubbisetty if (ath11k_dp_rx_h_verify_tkip_mic(ar, peer, first_frag)) 3356243874c6SManikanta Pubbisetty first_frag = NULL; 3357243874c6SManikanta Pubbisetty 3358243874c6SManikanta Pubbisetty *defrag_skb = first_frag; 3359243874c6SManikanta Pubbisetty return 0; 3360243874c6SManikanta Pubbisetty } 3361243874c6SManikanta Pubbisetty 3362243874c6SManikanta Pubbisetty static int ath11k_dp_rx_h_defrag_reo_reinject(struct ath11k *ar, struct dp_rx_tid *rx_tid, 3363243874c6SManikanta Pubbisetty struct sk_buff *defrag_skb) 3364243874c6SManikanta Pubbisetty { 3365243874c6SManikanta Pubbisetty struct ath11k_base *ab = ar->ab; 3366243874c6SManikanta Pubbisetty struct ath11k_pdev_dp *dp = &ar->dp; 3367243874c6SManikanta Pubbisetty struct dp_rxdma_ring *rx_refill_ring = &dp->rx_refill_buf_ring; 3368243874c6SManikanta Pubbisetty struct hal_rx_desc *rx_desc = (struct hal_rx_desc *)defrag_skb->data; 3369243874c6SManikanta Pubbisetty struct hal_reo_entrance_ring *reo_ent_ring; 3370243874c6SManikanta Pubbisetty struct hal_reo_dest_ring *reo_dest_ring; 3371243874c6SManikanta Pubbisetty struct dp_link_desc_bank *link_desc_banks; 3372243874c6SManikanta Pubbisetty struct hal_rx_msdu_link *msdu_link; 3373243874c6SManikanta Pubbisetty struct hal_rx_msdu_details *msdu0; 3374243874c6SManikanta Pubbisetty struct hal_srng *srng; 3375243874c6SManikanta Pubbisetty dma_addr_t paddr; 3376243874c6SManikanta Pubbisetty u32 desc_bank, msdu_info, mpdu_info; 3377e678fbd4SKarthikeyan Periyasamy u32 dst_idx, cookie, hal_rx_desc_sz; 3378243874c6SManikanta Pubbisetty int ret, buf_id; 3379243874c6SManikanta Pubbisetty 3380e678fbd4SKarthikeyan Periyasamy hal_rx_desc_sz = ab->hw_params.hal_desc_sz; 3381243874c6SManikanta Pubbisetty link_desc_banks = ab->dp.link_desc_banks; 3382243874c6SManikanta Pubbisetty reo_dest_ring = rx_tid->dst_ring_desc; 3383243874c6SManikanta Pubbisetty 3384243874c6SManikanta Pubbisetty ath11k_hal_rx_reo_ent_paddr_get(ab, reo_dest_ring, &paddr, &desc_bank); 3385243874c6SManikanta Pubbisetty msdu_link = (struct hal_rx_msdu_link *)(link_desc_banks[desc_bank].vaddr + 3386243874c6SManikanta Pubbisetty (paddr - link_desc_banks[desc_bank].paddr)); 3387243874c6SManikanta Pubbisetty msdu0 = &msdu_link->msdu_link[0]; 3388243874c6SManikanta Pubbisetty dst_idx = FIELD_GET(RX_MSDU_DESC_INFO0_REO_DEST_IND, msdu0->rx_msdu_info.info0); 3389243874c6SManikanta Pubbisetty memset(msdu0, 0, sizeof(*msdu0)); 3390243874c6SManikanta Pubbisetty 3391243874c6SManikanta Pubbisetty msdu_info = FIELD_PREP(RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU, 1) | 3392243874c6SManikanta Pubbisetty FIELD_PREP(RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU, 1) | 3393243874c6SManikanta Pubbisetty FIELD_PREP(RX_MSDU_DESC_INFO0_MSDU_CONTINUATION, 0) | 3394243874c6SManikanta Pubbisetty FIELD_PREP(RX_MSDU_DESC_INFO0_MSDU_LENGTH, 3395e678fbd4SKarthikeyan Periyasamy defrag_skb->len - hal_rx_desc_sz) | 3396243874c6SManikanta Pubbisetty FIELD_PREP(RX_MSDU_DESC_INFO0_REO_DEST_IND, dst_idx) | 3397243874c6SManikanta Pubbisetty FIELD_PREP(RX_MSDU_DESC_INFO0_VALID_SA, 1) | 3398243874c6SManikanta Pubbisetty FIELD_PREP(RX_MSDU_DESC_INFO0_VALID_DA, 1); 3399243874c6SManikanta Pubbisetty msdu0->rx_msdu_info.info0 = msdu_info; 3400243874c6SManikanta Pubbisetty 3401243874c6SManikanta Pubbisetty /* change msdu len in hal rx desc */ 3402e678fbd4SKarthikeyan Periyasamy ath11k_dp_rxdesc_set_msdu_len(ab, rx_desc, defrag_skb->len - hal_rx_desc_sz); 3403243874c6SManikanta Pubbisetty 3404243874c6SManikanta Pubbisetty paddr = dma_map_single(ab->dev, defrag_skb->data, 3405243874c6SManikanta Pubbisetty defrag_skb->len + skb_tailroom(defrag_skb), 340686a03dadSBaochen Qiang DMA_TO_DEVICE); 3407243874c6SManikanta Pubbisetty if (dma_mapping_error(ab->dev, paddr)) 3408243874c6SManikanta Pubbisetty return -ENOMEM; 3409243874c6SManikanta Pubbisetty 3410243874c6SManikanta Pubbisetty spin_lock_bh(&rx_refill_ring->idr_lock); 3411243874c6SManikanta Pubbisetty buf_id = idr_alloc(&rx_refill_ring->bufs_idr, defrag_skb, 0, 3412243874c6SManikanta Pubbisetty rx_refill_ring->bufs_max * 3, GFP_ATOMIC); 3413243874c6SManikanta Pubbisetty spin_unlock_bh(&rx_refill_ring->idr_lock); 3414243874c6SManikanta Pubbisetty if (buf_id < 0) { 3415243874c6SManikanta Pubbisetty ret = -ENOMEM; 3416243874c6SManikanta Pubbisetty goto err_unmap_dma; 3417243874c6SManikanta Pubbisetty } 3418243874c6SManikanta Pubbisetty 3419243874c6SManikanta Pubbisetty ATH11K_SKB_RXCB(defrag_skb)->paddr = paddr; 3420243874c6SManikanta Pubbisetty cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, dp->mac_id) | 3421243874c6SManikanta Pubbisetty FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id); 3422243874c6SManikanta Pubbisetty 3423734223d7SBaochen Qiang ath11k_hal_rx_buf_addr_info_set(msdu0, paddr, cookie, 3424734223d7SBaochen Qiang ab->hw_params.hal_params->rx_buf_rbm); 3425243874c6SManikanta Pubbisetty 3426243874c6SManikanta Pubbisetty /* Fill mpdu details into reo entrace ring */ 3427243874c6SManikanta Pubbisetty srng = &ab->hal.srng_list[ab->dp.reo_reinject_ring.ring_id]; 3428243874c6SManikanta Pubbisetty 3429243874c6SManikanta Pubbisetty spin_lock_bh(&srng->lock); 3430243874c6SManikanta Pubbisetty ath11k_hal_srng_access_begin(ab, srng); 3431243874c6SManikanta Pubbisetty 3432243874c6SManikanta Pubbisetty reo_ent_ring = (struct hal_reo_entrance_ring *) 3433243874c6SManikanta Pubbisetty ath11k_hal_srng_src_get_next_entry(ab, srng); 3434243874c6SManikanta Pubbisetty if (!reo_ent_ring) { 3435243874c6SManikanta Pubbisetty ath11k_hal_srng_access_end(ab, srng); 3436243874c6SManikanta Pubbisetty spin_unlock_bh(&srng->lock); 3437243874c6SManikanta Pubbisetty ret = -ENOSPC; 3438243874c6SManikanta Pubbisetty goto err_free_idr; 3439243874c6SManikanta Pubbisetty } 3440243874c6SManikanta Pubbisetty memset(reo_ent_ring, 0, sizeof(*reo_ent_ring)); 3441243874c6SManikanta Pubbisetty 3442243874c6SManikanta Pubbisetty ath11k_hal_rx_reo_ent_paddr_get(ab, reo_dest_ring, &paddr, &desc_bank); 3443243874c6SManikanta Pubbisetty ath11k_hal_rx_buf_addr_info_set(reo_ent_ring, paddr, desc_bank, 3444243874c6SManikanta Pubbisetty HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST); 3445243874c6SManikanta Pubbisetty 3446243874c6SManikanta Pubbisetty mpdu_info = FIELD_PREP(RX_MPDU_DESC_INFO0_MSDU_COUNT, 1) | 3447243874c6SManikanta Pubbisetty FIELD_PREP(RX_MPDU_DESC_INFO0_SEQ_NUM, rx_tid->cur_sn) | 3448243874c6SManikanta Pubbisetty FIELD_PREP(RX_MPDU_DESC_INFO0_FRAG_FLAG, 0) | 3449243874c6SManikanta Pubbisetty FIELD_PREP(RX_MPDU_DESC_INFO0_VALID_SA, 1) | 3450243874c6SManikanta Pubbisetty FIELD_PREP(RX_MPDU_DESC_INFO0_VALID_DA, 1) | 3451243874c6SManikanta Pubbisetty FIELD_PREP(RX_MPDU_DESC_INFO0_RAW_MPDU, 1) | 3452243874c6SManikanta Pubbisetty FIELD_PREP(RX_MPDU_DESC_INFO0_VALID_PN, 1); 3453243874c6SManikanta Pubbisetty 3454243874c6SManikanta Pubbisetty reo_ent_ring->rx_mpdu_info.info0 = mpdu_info; 3455243874c6SManikanta Pubbisetty reo_ent_ring->rx_mpdu_info.meta_data = reo_dest_ring->rx_mpdu_info.meta_data; 3456243874c6SManikanta Pubbisetty reo_ent_ring->queue_addr_lo = reo_dest_ring->queue_addr_lo; 3457243874c6SManikanta Pubbisetty reo_ent_ring->info0 = FIELD_PREP(HAL_REO_ENTR_RING_INFO0_QUEUE_ADDR_HI, 3458243874c6SManikanta Pubbisetty FIELD_GET(HAL_REO_DEST_RING_INFO0_QUEUE_ADDR_HI, 3459243874c6SManikanta Pubbisetty reo_dest_ring->info0)) | 3460243874c6SManikanta Pubbisetty FIELD_PREP(HAL_REO_ENTR_RING_INFO0_DEST_IND, dst_idx); 3461243874c6SManikanta Pubbisetty ath11k_hal_srng_access_end(ab, srng); 3462243874c6SManikanta Pubbisetty spin_unlock_bh(&srng->lock); 3463243874c6SManikanta Pubbisetty 3464243874c6SManikanta Pubbisetty return 0; 3465243874c6SManikanta Pubbisetty 3466243874c6SManikanta Pubbisetty err_free_idr: 3467243874c6SManikanta Pubbisetty spin_lock_bh(&rx_refill_ring->idr_lock); 3468243874c6SManikanta Pubbisetty idr_remove(&rx_refill_ring->bufs_idr, buf_id); 3469243874c6SManikanta Pubbisetty spin_unlock_bh(&rx_refill_ring->idr_lock); 3470243874c6SManikanta Pubbisetty err_unmap_dma: 3471243874c6SManikanta Pubbisetty dma_unmap_single(ab->dev, paddr, defrag_skb->len + skb_tailroom(defrag_skb), 347286a03dadSBaochen Qiang DMA_TO_DEVICE); 3473243874c6SManikanta Pubbisetty return ret; 3474243874c6SManikanta Pubbisetty } 3475243874c6SManikanta Pubbisetty 3476e678fbd4SKarthikeyan Periyasamy static int ath11k_dp_rx_h_cmp_frags(struct ath11k *ar, 3477e678fbd4SKarthikeyan Periyasamy struct sk_buff *a, struct sk_buff *b) 3478243874c6SManikanta Pubbisetty { 3479243874c6SManikanta Pubbisetty int frag1, frag2; 3480243874c6SManikanta Pubbisetty 3481e678fbd4SKarthikeyan Periyasamy frag1 = ath11k_dp_rx_h_mpdu_start_frag_no(ar->ab, a); 3482e678fbd4SKarthikeyan Periyasamy frag2 = ath11k_dp_rx_h_mpdu_start_frag_no(ar->ab, b); 3483243874c6SManikanta Pubbisetty 3484243874c6SManikanta Pubbisetty return frag1 - frag2; 3485243874c6SManikanta Pubbisetty } 3486243874c6SManikanta Pubbisetty 3487e678fbd4SKarthikeyan Periyasamy static void ath11k_dp_rx_h_sort_frags(struct ath11k *ar, 3488e678fbd4SKarthikeyan Periyasamy struct sk_buff_head *frag_list, 3489243874c6SManikanta Pubbisetty struct sk_buff *cur_frag) 3490243874c6SManikanta Pubbisetty { 3491243874c6SManikanta Pubbisetty struct sk_buff *skb; 3492243874c6SManikanta Pubbisetty int cmp; 3493243874c6SManikanta Pubbisetty 3494243874c6SManikanta Pubbisetty skb_queue_walk(frag_list, skb) { 3495e678fbd4SKarthikeyan Periyasamy cmp = ath11k_dp_rx_h_cmp_frags(ar, skb, cur_frag); 3496243874c6SManikanta Pubbisetty if (cmp < 0) 3497243874c6SManikanta Pubbisetty continue; 3498243874c6SManikanta Pubbisetty __skb_queue_before(frag_list, skb, cur_frag); 3499243874c6SManikanta Pubbisetty return; 3500243874c6SManikanta Pubbisetty } 3501243874c6SManikanta Pubbisetty __skb_queue_tail(frag_list, cur_frag); 3502243874c6SManikanta Pubbisetty } 3503243874c6SManikanta Pubbisetty 3504e678fbd4SKarthikeyan Periyasamy static u64 ath11k_dp_rx_h_get_pn(struct ath11k *ar, struct sk_buff *skb) 3505243874c6SManikanta Pubbisetty { 3506243874c6SManikanta Pubbisetty struct ieee80211_hdr *hdr; 3507243874c6SManikanta Pubbisetty u64 pn = 0; 3508243874c6SManikanta Pubbisetty u8 *ehdr; 3509e678fbd4SKarthikeyan Periyasamy u32 hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz; 3510243874c6SManikanta Pubbisetty 3511e678fbd4SKarthikeyan Periyasamy hdr = (struct ieee80211_hdr *)(skb->data + hal_rx_desc_sz); 3512e678fbd4SKarthikeyan Periyasamy ehdr = skb->data + hal_rx_desc_sz + ieee80211_hdrlen(hdr->frame_control); 3513243874c6SManikanta Pubbisetty 3514243874c6SManikanta Pubbisetty pn = ehdr[0]; 3515243874c6SManikanta Pubbisetty pn |= (u64)ehdr[1] << 8; 3516243874c6SManikanta Pubbisetty pn |= (u64)ehdr[4] << 16; 3517243874c6SManikanta Pubbisetty pn |= (u64)ehdr[5] << 24; 3518243874c6SManikanta Pubbisetty pn |= (u64)ehdr[6] << 32; 3519243874c6SManikanta Pubbisetty pn |= (u64)ehdr[7] << 40; 3520243874c6SManikanta Pubbisetty 3521243874c6SManikanta Pubbisetty return pn; 3522243874c6SManikanta Pubbisetty } 3523243874c6SManikanta Pubbisetty 3524243874c6SManikanta Pubbisetty static bool 3525243874c6SManikanta Pubbisetty ath11k_dp_rx_h_defrag_validate_incr_pn(struct ath11k *ar, struct dp_rx_tid *rx_tid) 3526243874c6SManikanta Pubbisetty { 3527243874c6SManikanta Pubbisetty enum hal_encrypt_type encrypt_type; 3528243874c6SManikanta Pubbisetty struct sk_buff *first_frag, *skb; 3529243874c6SManikanta Pubbisetty struct hal_rx_desc *desc; 3530243874c6SManikanta Pubbisetty u64 last_pn; 3531243874c6SManikanta Pubbisetty u64 cur_pn; 3532243874c6SManikanta Pubbisetty 3533243874c6SManikanta Pubbisetty first_frag = skb_peek(&rx_tid->rx_frags); 3534243874c6SManikanta Pubbisetty desc = (struct hal_rx_desc *)first_frag->data; 3535243874c6SManikanta Pubbisetty 3536e678fbd4SKarthikeyan Periyasamy encrypt_type = ath11k_dp_rx_h_mpdu_start_enctype(ar->ab, desc); 3537243874c6SManikanta Pubbisetty if (encrypt_type != HAL_ENCRYPT_TYPE_CCMP_128 && 3538243874c6SManikanta Pubbisetty encrypt_type != HAL_ENCRYPT_TYPE_CCMP_256 && 3539243874c6SManikanta Pubbisetty encrypt_type != HAL_ENCRYPT_TYPE_GCMP_128 && 3540243874c6SManikanta Pubbisetty encrypt_type != HAL_ENCRYPT_TYPE_AES_GCMP_256) 3541243874c6SManikanta Pubbisetty return true; 3542243874c6SManikanta Pubbisetty 3543e678fbd4SKarthikeyan Periyasamy last_pn = ath11k_dp_rx_h_get_pn(ar, first_frag); 3544243874c6SManikanta Pubbisetty skb_queue_walk(&rx_tid->rx_frags, skb) { 3545243874c6SManikanta Pubbisetty if (skb == first_frag) 3546243874c6SManikanta Pubbisetty continue; 3547243874c6SManikanta Pubbisetty 3548e678fbd4SKarthikeyan Periyasamy cur_pn = ath11k_dp_rx_h_get_pn(ar, skb); 3549243874c6SManikanta Pubbisetty if (cur_pn != last_pn + 1) 3550243874c6SManikanta Pubbisetty return false; 3551243874c6SManikanta Pubbisetty last_pn = cur_pn; 3552243874c6SManikanta Pubbisetty } 3553243874c6SManikanta Pubbisetty return true; 3554243874c6SManikanta Pubbisetty } 3555243874c6SManikanta Pubbisetty 3556243874c6SManikanta Pubbisetty static int ath11k_dp_rx_frag_h_mpdu(struct ath11k *ar, 3557243874c6SManikanta Pubbisetty struct sk_buff *msdu, 3558243874c6SManikanta Pubbisetty u32 *ring_desc) 3559243874c6SManikanta Pubbisetty { 3560243874c6SManikanta Pubbisetty struct ath11k_base *ab = ar->ab; 3561243874c6SManikanta Pubbisetty struct hal_rx_desc *rx_desc; 3562243874c6SManikanta Pubbisetty struct ath11k_peer *peer; 3563243874c6SManikanta Pubbisetty struct dp_rx_tid *rx_tid; 3564243874c6SManikanta Pubbisetty struct sk_buff *defrag_skb = NULL; 3565243874c6SManikanta Pubbisetty u32 peer_id; 3566243874c6SManikanta Pubbisetty u16 seqno, frag_no; 3567243874c6SManikanta Pubbisetty u8 tid; 3568243874c6SManikanta Pubbisetty int ret = 0; 3569243874c6SManikanta Pubbisetty bool more_frags; 3570210f563bSSriram R bool is_mcbc; 3571243874c6SManikanta Pubbisetty 3572243874c6SManikanta Pubbisetty rx_desc = (struct hal_rx_desc *)msdu->data; 3573e678fbd4SKarthikeyan Periyasamy peer_id = ath11k_dp_rx_h_mpdu_start_peer_id(ar->ab, rx_desc); 3574e678fbd4SKarthikeyan Periyasamy tid = ath11k_dp_rx_h_mpdu_start_tid(ar->ab, rx_desc); 3575e678fbd4SKarthikeyan Periyasamy seqno = ath11k_dp_rx_h_mpdu_start_seq_no(ar->ab, rx_desc); 3576e678fbd4SKarthikeyan Periyasamy frag_no = ath11k_dp_rx_h_mpdu_start_frag_no(ar->ab, msdu); 3577e678fbd4SKarthikeyan Periyasamy more_frags = ath11k_dp_rx_h_mpdu_start_more_frags(ar->ab, msdu); 3578210f563bSSriram R is_mcbc = ath11k_dp_rx_h_attn_is_mcbc(ar->ab, rx_desc); 3579210f563bSSriram R 3580210f563bSSriram R /* Multicast/Broadcast fragments are not expected */ 3581210f563bSSriram R if (is_mcbc) 3582210f563bSSriram R return -EINVAL; 3583243874c6SManikanta Pubbisetty 3584e678fbd4SKarthikeyan Periyasamy if (!ath11k_dp_rx_h_mpdu_start_seq_ctrl_valid(ar->ab, rx_desc) || 3585e678fbd4SKarthikeyan Periyasamy !ath11k_dp_rx_h_mpdu_start_fc_valid(ar->ab, rx_desc) || 3586243874c6SManikanta Pubbisetty tid > IEEE80211_NUM_TIDS) 3587243874c6SManikanta Pubbisetty return -EINVAL; 3588243874c6SManikanta Pubbisetty 3589243874c6SManikanta Pubbisetty /* received unfragmented packet in reo 3590243874c6SManikanta Pubbisetty * exception ring, this shouldn't happen 3591243874c6SManikanta Pubbisetty * as these packets typically come from 3592243874c6SManikanta Pubbisetty * reo2sw srngs. 3593243874c6SManikanta Pubbisetty */ 3594243874c6SManikanta Pubbisetty if (WARN_ON_ONCE(!frag_no && !more_frags)) 3595243874c6SManikanta Pubbisetty return -EINVAL; 3596243874c6SManikanta Pubbisetty 3597243874c6SManikanta Pubbisetty spin_lock_bh(&ab->base_lock); 3598243874c6SManikanta Pubbisetty peer = ath11k_peer_find_by_id(ab, peer_id); 3599243874c6SManikanta Pubbisetty if (!peer) { 3600243874c6SManikanta Pubbisetty ath11k_warn(ab, "failed to find the peer to de-fragment received fragment peer_id %d\n", 3601243874c6SManikanta Pubbisetty peer_id); 3602243874c6SManikanta Pubbisetty ret = -ENOENT; 3603243874c6SManikanta Pubbisetty goto out_unlock; 3604243874c6SManikanta Pubbisetty } 3605a06bfb3cSHarshitha Prem if (!peer->dp_setup_done) { 3606a06bfb3cSHarshitha Prem ath11k_warn(ab, "The peer %pM [%d] has uninitialized datapath\n", 3607a06bfb3cSHarshitha Prem peer->addr, peer_id); 3608a06bfb3cSHarshitha Prem ret = -ENOENT; 3609a06bfb3cSHarshitha Prem goto out_unlock; 3610a06bfb3cSHarshitha Prem } 3611a06bfb3cSHarshitha Prem 3612243874c6SManikanta Pubbisetty rx_tid = &peer->rx_tid[tid]; 3613243874c6SManikanta Pubbisetty 3614243874c6SManikanta Pubbisetty if ((!skb_queue_empty(&rx_tid->rx_frags) && seqno != rx_tid->cur_sn) || 3615243874c6SManikanta Pubbisetty skb_queue_empty(&rx_tid->rx_frags)) { 3616243874c6SManikanta Pubbisetty /* Flush stored fragments and start a new sequence */ 3617243874c6SManikanta Pubbisetty ath11k_dp_rx_frags_cleanup(rx_tid, true); 3618243874c6SManikanta Pubbisetty rx_tid->cur_sn = seqno; 3619243874c6SManikanta Pubbisetty } 3620243874c6SManikanta Pubbisetty 3621243874c6SManikanta Pubbisetty if (rx_tid->rx_frag_bitmap & BIT(frag_no)) { 3622243874c6SManikanta Pubbisetty /* Fragment already present */ 3623243874c6SManikanta Pubbisetty ret = -EINVAL; 3624243874c6SManikanta Pubbisetty goto out_unlock; 3625243874c6SManikanta Pubbisetty } 3626243874c6SManikanta Pubbisetty 362741e02bf4SHarshitha Prem if (!rx_tid->rx_frag_bitmap || (frag_no > __fls(rx_tid->rx_frag_bitmap))) 3628243874c6SManikanta Pubbisetty __skb_queue_tail(&rx_tid->rx_frags, msdu); 3629243874c6SManikanta Pubbisetty else 3630e678fbd4SKarthikeyan Periyasamy ath11k_dp_rx_h_sort_frags(ar, &rx_tid->rx_frags, msdu); 3631243874c6SManikanta Pubbisetty 3632243874c6SManikanta Pubbisetty rx_tid->rx_frag_bitmap |= BIT(frag_no); 3633243874c6SManikanta Pubbisetty if (!more_frags) 3634243874c6SManikanta Pubbisetty rx_tid->last_frag_no = frag_no; 3635243874c6SManikanta Pubbisetty 3636243874c6SManikanta Pubbisetty if (frag_no == 0) { 3637243874c6SManikanta Pubbisetty rx_tid->dst_ring_desc = kmemdup(ring_desc, 3638243874c6SManikanta Pubbisetty sizeof(*rx_tid->dst_ring_desc), 3639243874c6SManikanta Pubbisetty GFP_ATOMIC); 3640243874c6SManikanta Pubbisetty if (!rx_tid->dst_ring_desc) { 3641243874c6SManikanta Pubbisetty ret = -ENOMEM; 3642243874c6SManikanta Pubbisetty goto out_unlock; 3643243874c6SManikanta Pubbisetty } 3644243874c6SManikanta Pubbisetty } else { 3645243874c6SManikanta Pubbisetty ath11k_dp_rx_link_desc_return(ab, ring_desc, 3646243874c6SManikanta Pubbisetty HAL_WBM_REL_BM_ACT_PUT_IN_IDLE); 3647243874c6SManikanta Pubbisetty } 3648243874c6SManikanta Pubbisetty 3649243874c6SManikanta Pubbisetty if (!rx_tid->last_frag_no || 3650243874c6SManikanta Pubbisetty rx_tid->rx_frag_bitmap != GENMASK(rx_tid->last_frag_no, 0)) { 3651243874c6SManikanta Pubbisetty mod_timer(&rx_tid->frag_timer, jiffies + 3652243874c6SManikanta Pubbisetty ATH11K_DP_RX_FRAGMENT_TIMEOUT_MS); 3653243874c6SManikanta Pubbisetty goto out_unlock; 3654243874c6SManikanta Pubbisetty } 3655243874c6SManikanta Pubbisetty 3656243874c6SManikanta Pubbisetty spin_unlock_bh(&ab->base_lock); 3657243874c6SManikanta Pubbisetty del_timer_sync(&rx_tid->frag_timer); 3658243874c6SManikanta Pubbisetty spin_lock_bh(&ab->base_lock); 3659243874c6SManikanta Pubbisetty 3660243874c6SManikanta Pubbisetty peer = ath11k_peer_find_by_id(ab, peer_id); 3661243874c6SManikanta Pubbisetty if (!peer) 3662243874c6SManikanta Pubbisetty goto err_frags_cleanup; 3663243874c6SManikanta Pubbisetty 3664243874c6SManikanta Pubbisetty if (!ath11k_dp_rx_h_defrag_validate_incr_pn(ar, rx_tid)) 3665243874c6SManikanta Pubbisetty goto err_frags_cleanup; 3666243874c6SManikanta Pubbisetty 3667243874c6SManikanta Pubbisetty if (ath11k_dp_rx_h_defrag(ar, peer, rx_tid, &defrag_skb)) 3668243874c6SManikanta Pubbisetty goto err_frags_cleanup; 3669243874c6SManikanta Pubbisetty 3670243874c6SManikanta Pubbisetty if (!defrag_skb) 3671243874c6SManikanta Pubbisetty goto err_frags_cleanup; 3672243874c6SManikanta Pubbisetty 3673243874c6SManikanta Pubbisetty if (ath11k_dp_rx_h_defrag_reo_reinject(ar, rx_tid, defrag_skb)) 3674243874c6SManikanta Pubbisetty goto err_frags_cleanup; 3675243874c6SManikanta Pubbisetty 3676243874c6SManikanta Pubbisetty ath11k_dp_rx_frags_cleanup(rx_tid, false); 3677243874c6SManikanta Pubbisetty goto out_unlock; 3678243874c6SManikanta Pubbisetty 3679243874c6SManikanta Pubbisetty err_frags_cleanup: 3680243874c6SManikanta Pubbisetty dev_kfree_skb_any(defrag_skb); 3681243874c6SManikanta Pubbisetty ath11k_dp_rx_frags_cleanup(rx_tid, true); 3682243874c6SManikanta Pubbisetty out_unlock: 3683243874c6SManikanta Pubbisetty spin_unlock_bh(&ab->base_lock); 3684243874c6SManikanta Pubbisetty return ret; 3685243874c6SManikanta Pubbisetty } 3686243874c6SManikanta Pubbisetty 3687d5c65159SKalle Valo static int 3688243874c6SManikanta Pubbisetty ath11k_dp_process_rx_err_buf(struct ath11k *ar, u32 *ring_desc, int buf_id, bool drop) 3689d5c65159SKalle Valo { 3690d5c65159SKalle Valo struct ath11k_pdev_dp *dp = &ar->dp; 3691d5c65159SKalle Valo struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; 3692d5c65159SKalle Valo struct sk_buff *msdu; 3693d5c65159SKalle Valo struct ath11k_skb_rxcb *rxcb; 3694d5c65159SKalle Valo struct hal_rx_desc *rx_desc; 3695d7d43782STamizh Chelvam u8 *hdr_status; 3696d5c65159SKalle Valo u16 msdu_len; 3697e678fbd4SKarthikeyan Periyasamy u32 hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz; 3698d5c65159SKalle Valo 3699d5c65159SKalle Valo spin_lock_bh(&rx_ring->idr_lock); 3700d5c65159SKalle Valo msdu = idr_find(&rx_ring->bufs_idr, buf_id); 3701d5c65159SKalle Valo if (!msdu) { 3702d5c65159SKalle Valo ath11k_warn(ar->ab, "rx err buf with invalid buf_id %d\n", 3703d5c65159SKalle Valo buf_id); 3704d5c65159SKalle Valo spin_unlock_bh(&rx_ring->idr_lock); 3705d5c65159SKalle Valo return -EINVAL; 3706d5c65159SKalle Valo } 3707d5c65159SKalle Valo 3708d5c65159SKalle Valo idr_remove(&rx_ring->bufs_idr, buf_id); 3709d5c65159SKalle Valo spin_unlock_bh(&rx_ring->idr_lock); 3710d5c65159SKalle Valo 3711d5c65159SKalle Valo rxcb = ATH11K_SKB_RXCB(msdu); 3712d5c65159SKalle Valo dma_unmap_single(ar->ab->dev, rxcb->paddr, 3713d5c65159SKalle Valo msdu->len + skb_tailroom(msdu), 3714d5c65159SKalle Valo DMA_FROM_DEVICE); 3715d5c65159SKalle Valo 3716243874c6SManikanta Pubbisetty if (drop) { 3717d5c65159SKalle Valo dev_kfree_skb_any(msdu); 3718d5c65159SKalle Valo return 0; 3719d5c65159SKalle Valo } 3720d5c65159SKalle Valo 3721d5c65159SKalle Valo rcu_read_lock(); 3722d5c65159SKalle Valo if (!rcu_dereference(ar->ab->pdevs_active[ar->pdev_idx])) { 3723d5c65159SKalle Valo dev_kfree_skb_any(msdu); 3724d5c65159SKalle Valo goto exit; 3725d5c65159SKalle Valo } 3726d5c65159SKalle Valo 3727d5c65159SKalle Valo if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) { 3728d5c65159SKalle Valo dev_kfree_skb_any(msdu); 3729d5c65159SKalle Valo goto exit; 3730d5c65159SKalle Valo } 3731d5c65159SKalle Valo 3732d5c65159SKalle Valo rx_desc = (struct hal_rx_desc *)msdu->data; 3733e678fbd4SKarthikeyan Periyasamy msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(ar->ab, rx_desc); 3734e678fbd4SKarthikeyan Periyasamy if ((msdu_len + hal_rx_desc_sz) > DP_RX_BUFFER_SIZE) { 3735e678fbd4SKarthikeyan Periyasamy hdr_status = ath11k_dp_rx_h_80211_hdr(ar->ab, rx_desc); 3736d7d43782STamizh Chelvam ath11k_warn(ar->ab, "invalid msdu leng %u", msdu_len); 3737d7d43782STamizh Chelvam ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", hdr_status, 3738d7d43782STamizh Chelvam sizeof(struct ieee80211_hdr)); 3739d7d43782STamizh Chelvam ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", rx_desc, 3740d7d43782STamizh Chelvam sizeof(struct hal_rx_desc)); 3741d7d43782STamizh Chelvam dev_kfree_skb_any(msdu); 3742d7d43782STamizh Chelvam goto exit; 3743d7d43782STamizh Chelvam } 3744d7d43782STamizh Chelvam 3745e678fbd4SKarthikeyan Periyasamy skb_put(msdu, hal_rx_desc_sz + msdu_len); 3746d5c65159SKalle Valo 3747243874c6SManikanta Pubbisetty if (ath11k_dp_rx_frag_h_mpdu(ar, msdu, ring_desc)) { 3748243874c6SManikanta Pubbisetty dev_kfree_skb_any(msdu); 3749243874c6SManikanta Pubbisetty ath11k_dp_rx_link_desc_return(ar->ab, ring_desc, 3750243874c6SManikanta Pubbisetty HAL_WBM_REL_BM_ACT_PUT_IN_IDLE); 3751243874c6SManikanta Pubbisetty } 3752d5c65159SKalle Valo exit: 3753d5c65159SKalle Valo rcu_read_unlock(); 3754d5c65159SKalle Valo return 0; 3755d5c65159SKalle Valo } 3756d5c65159SKalle Valo 3757d5c65159SKalle Valo int ath11k_dp_process_rx_err(struct ath11k_base *ab, struct napi_struct *napi, 3758d5c65159SKalle Valo int budget) 3759d5c65159SKalle Valo { 3760293cb583SJohn Crispin u32 msdu_cookies[HAL_NUM_RX_MSDUS_PER_LINK_DESC]; 3761d5c65159SKalle Valo struct dp_link_desc_bank *link_desc_banks; 3762d5c65159SKalle Valo enum hal_rx_buf_return_buf_manager rbm; 3763d5c65159SKalle Valo int tot_n_bufs_reaped, quota, ret, i; 3764d5c65159SKalle Valo int n_bufs_reaped[MAX_RADIOS] = {0}; 3765d5c65159SKalle Valo struct dp_rxdma_ring *rx_ring; 3766d5c65159SKalle Valo struct dp_srng *reo_except; 3767d5c65159SKalle Valo u32 desc_bank, num_msdus; 3768d5c65159SKalle Valo struct hal_srng *srng; 3769d5c65159SKalle Valo struct ath11k_dp *dp; 3770d5c65159SKalle Valo void *link_desc_va; 3771d5c65159SKalle Valo int buf_id, mac_id; 3772d5c65159SKalle Valo struct ath11k *ar; 3773d5c65159SKalle Valo dma_addr_t paddr; 3774d5c65159SKalle Valo u32 *desc; 3775d5c65159SKalle Valo bool is_frag; 3776243874c6SManikanta Pubbisetty u8 drop = 0; 3777d5c65159SKalle Valo 3778d5c65159SKalle Valo tot_n_bufs_reaped = 0; 3779d5c65159SKalle Valo quota = budget; 3780d5c65159SKalle Valo 3781d5c65159SKalle Valo dp = &ab->dp; 3782d5c65159SKalle Valo reo_except = &dp->reo_except_ring; 3783d5c65159SKalle Valo link_desc_banks = dp->link_desc_banks; 3784d5c65159SKalle Valo 3785d5c65159SKalle Valo srng = &ab->hal.srng_list[reo_except->ring_id]; 3786d5c65159SKalle Valo 3787d5c65159SKalle Valo spin_lock_bh(&srng->lock); 3788d5c65159SKalle Valo 3789d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 3790d5c65159SKalle Valo 3791d5c65159SKalle Valo while (budget && 3792d5c65159SKalle Valo (desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) { 3793293cb583SJohn Crispin struct hal_reo_dest_ring *reo_desc = (struct hal_reo_dest_ring *)desc; 3794293cb583SJohn Crispin 3795d5c65159SKalle Valo ab->soc_stats.err_ring_pkts++; 3796d5c65159SKalle Valo ret = ath11k_hal_desc_reo_parse_err(ab, desc, &paddr, 3797d5c65159SKalle Valo &desc_bank); 3798d5c65159SKalle Valo if (ret) { 3799d5c65159SKalle Valo ath11k_warn(ab, "failed to parse error reo desc %d\n", 3800d5c65159SKalle Valo ret); 3801d5c65159SKalle Valo continue; 3802d5c65159SKalle Valo } 3803d5c65159SKalle Valo link_desc_va = link_desc_banks[desc_bank].vaddr + 3804d5c65159SKalle Valo (paddr - link_desc_banks[desc_bank].paddr); 3805293cb583SJohn Crispin ath11k_hal_rx_msdu_link_info_get(link_desc_va, &num_msdus, msdu_cookies, 3806d5c65159SKalle Valo &rbm); 3807d5c65159SKalle Valo if (rbm != HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST && 380871c748b5SBaochen Qiang rbm != HAL_RX_BUF_RBM_SW3_BM) { 3809d5c65159SKalle Valo ab->soc_stats.invalid_rbm++; 3810d5c65159SKalle Valo ath11k_warn(ab, "invalid return buffer manager %d\n", rbm); 3811d5c65159SKalle Valo ath11k_dp_rx_link_desc_return(ab, desc, 3812d5c65159SKalle Valo HAL_WBM_REL_BM_ACT_REL_MSDU); 3813d5c65159SKalle Valo continue; 3814d5c65159SKalle Valo } 3815d5c65159SKalle Valo 3816293cb583SJohn Crispin is_frag = !!(reo_desc->rx_mpdu_info.info0 & RX_MPDU_DESC_INFO0_FRAG_FLAG); 3817d5c65159SKalle Valo 3818243874c6SManikanta Pubbisetty /* Process only rx fragments with one msdu per link desc below, and drop 3819243874c6SManikanta Pubbisetty * msdu's indicated due to error reasons. 3820243874c6SManikanta Pubbisetty */ 3821243874c6SManikanta Pubbisetty if (!is_frag || num_msdus > 1) { 3822243874c6SManikanta Pubbisetty drop = 1; 3823d5c65159SKalle Valo /* Return the link desc back to wbm idle list */ 3824d5c65159SKalle Valo ath11k_dp_rx_link_desc_return(ab, desc, 3825d5c65159SKalle Valo HAL_WBM_REL_BM_ACT_PUT_IN_IDLE); 3826243874c6SManikanta Pubbisetty } 3827d5c65159SKalle Valo 3828d5c65159SKalle Valo for (i = 0; i < num_msdus; i++) { 3829d5c65159SKalle Valo buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, 3830293cb583SJohn Crispin msdu_cookies[i]); 3831d5c65159SKalle Valo 3832d5c65159SKalle Valo mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, 3833293cb583SJohn Crispin msdu_cookies[i]); 3834d5c65159SKalle Valo 3835d5c65159SKalle Valo ar = ab->pdevs[mac_id].ar; 3836d5c65159SKalle Valo 3837243874c6SManikanta Pubbisetty if (!ath11k_dp_process_rx_err_buf(ar, desc, buf_id, drop)) { 3838d5c65159SKalle Valo n_bufs_reaped[mac_id]++; 3839d5c65159SKalle Valo tot_n_bufs_reaped++; 3840d5c65159SKalle Valo } 3841d5c65159SKalle Valo } 3842d5c65159SKalle Valo 3843d5c65159SKalle Valo if (tot_n_bufs_reaped >= quota) { 3844d5c65159SKalle Valo tot_n_bufs_reaped = quota; 3845d5c65159SKalle Valo goto exit; 3846d5c65159SKalle Valo } 3847d5c65159SKalle Valo 3848d5c65159SKalle Valo budget = quota - tot_n_bufs_reaped; 3849d5c65159SKalle Valo } 3850d5c65159SKalle Valo 3851d5c65159SKalle Valo exit: 3852d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 3853d5c65159SKalle Valo 3854d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 3855d5c65159SKalle Valo 3856d5c65159SKalle Valo for (i = 0; i < ab->num_radios; i++) { 3857d5c65159SKalle Valo if (!n_bufs_reaped[i]) 3858d5c65159SKalle Valo continue; 3859d5c65159SKalle Valo 3860d5c65159SKalle Valo ar = ab->pdevs[i].ar; 3861d5c65159SKalle Valo rx_ring = &ar->dp.rx_refill_buf_ring; 3862d5c65159SKalle Valo 3863d5c65159SKalle Valo ath11k_dp_rxbufs_replenish(ab, i, rx_ring, n_bufs_reaped[i], 3864734223d7SBaochen Qiang ab->hw_params.hal_params->rx_buf_rbm); 3865d5c65159SKalle Valo } 3866d5c65159SKalle Valo 3867d5c65159SKalle Valo return tot_n_bufs_reaped; 3868d5c65159SKalle Valo } 3869d5c65159SKalle Valo 3870d5c65159SKalle Valo static void ath11k_dp_rx_null_q_desc_sg_drop(struct ath11k *ar, 3871d5c65159SKalle Valo int msdu_len, 3872d5c65159SKalle Valo struct sk_buff_head *msdu_list) 3873d5c65159SKalle Valo { 3874d5c65159SKalle Valo struct sk_buff *skb, *tmp; 3875d5c65159SKalle Valo struct ath11k_skb_rxcb *rxcb; 3876d5c65159SKalle Valo int n_buffs; 3877d5c65159SKalle Valo 3878d5c65159SKalle Valo n_buffs = DIV_ROUND_UP(msdu_len, 3879e678fbd4SKarthikeyan Periyasamy (DP_RX_BUFFER_SIZE - ar->ab->hw_params.hal_desc_sz)); 3880d5c65159SKalle Valo 3881d5c65159SKalle Valo skb_queue_walk_safe(msdu_list, skb, tmp) { 3882d5c65159SKalle Valo rxcb = ATH11K_SKB_RXCB(skb); 3883d5c65159SKalle Valo if (rxcb->err_rel_src == HAL_WBM_REL_SRC_MODULE_REO && 3884d5c65159SKalle Valo rxcb->err_code == HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO) { 3885d5c65159SKalle Valo if (!n_buffs) 3886d5c65159SKalle Valo break; 3887d5c65159SKalle Valo __skb_unlink(skb, msdu_list); 3888d5c65159SKalle Valo dev_kfree_skb_any(skb); 3889d5c65159SKalle Valo n_buffs--; 3890d5c65159SKalle Valo } 3891d5c65159SKalle Valo } 3892d5c65159SKalle Valo } 3893d5c65159SKalle Valo 3894d5c65159SKalle Valo static int ath11k_dp_rx_h_null_q_desc(struct ath11k *ar, struct sk_buff *msdu, 3895d5c65159SKalle Valo struct ieee80211_rx_status *status, 3896d5c65159SKalle Valo struct sk_buff_head *msdu_list) 3897d5c65159SKalle Valo { 3898d5c65159SKalle Valo u16 msdu_len; 3899d5c65159SKalle Valo struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data; 3900e678fbd4SKarthikeyan Periyasamy struct rx_attention *rx_attention; 3901d5c65159SKalle Valo u8 l3pad_bytes; 3902d5c65159SKalle Valo struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 3903e678fbd4SKarthikeyan Periyasamy u32 hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz; 3904d5c65159SKalle Valo 3905e678fbd4SKarthikeyan Periyasamy msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(ar->ab, desc); 3906d5c65159SKalle Valo 3907e678fbd4SKarthikeyan Periyasamy if (!rxcb->is_frag && ((msdu_len + hal_rx_desc_sz) > DP_RX_BUFFER_SIZE)) { 3908d5c65159SKalle Valo /* First buffer will be freed by the caller, so deduct it's length */ 3909e678fbd4SKarthikeyan Periyasamy msdu_len = msdu_len - (DP_RX_BUFFER_SIZE - hal_rx_desc_sz); 3910d5c65159SKalle Valo ath11k_dp_rx_null_q_desc_sg_drop(ar, msdu_len, msdu_list); 3911d5c65159SKalle Valo return -EINVAL; 3912d5c65159SKalle Valo } 3913d5c65159SKalle Valo 3914e678fbd4SKarthikeyan Periyasamy rx_attention = ath11k_dp_rx_get_attention(ar->ab, desc); 3915e678fbd4SKarthikeyan Periyasamy if (!ath11k_dp_rx_h_attn_msdu_done(rx_attention)) { 3916d5c65159SKalle Valo ath11k_warn(ar->ab, 3917d5c65159SKalle Valo "msdu_done bit not set in null_q_des processing\n"); 3918d5c65159SKalle Valo __skb_queue_purge(msdu_list); 3919d5c65159SKalle Valo return -EIO; 3920d5c65159SKalle Valo } 3921d5c65159SKalle Valo 3922d5c65159SKalle Valo /* Handle NULL queue descriptor violations arising out a missing 3923d5c65159SKalle Valo * REO queue for a given peer or a given TID. This typically 3924d5c65159SKalle Valo * may happen if a packet is received on a QOS enabled TID before the 3925d5c65159SKalle Valo * ADDBA negotiation for that TID, when the TID queue is setup. Or 3926d5c65159SKalle Valo * it may also happen for MC/BC frames if they are not routed to the 3927d5c65159SKalle Valo * non-QOS TID queue, in the absence of any other default TID queue. 3928d5c65159SKalle Valo * This error can show up both in a REO destination or WBM release ring. 3929d5c65159SKalle Valo */ 3930d5c65159SKalle Valo 3931e678fbd4SKarthikeyan Periyasamy rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(ar->ab, desc); 3932e678fbd4SKarthikeyan Periyasamy rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(ar->ab, desc); 3933d5c65159SKalle Valo 3934243874c6SManikanta Pubbisetty if (rxcb->is_frag) { 3935e678fbd4SKarthikeyan Periyasamy skb_pull(msdu, hal_rx_desc_sz); 3936243874c6SManikanta Pubbisetty } else { 3937e678fbd4SKarthikeyan Periyasamy l3pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, desc); 3938d5c65159SKalle Valo 3939e678fbd4SKarthikeyan Periyasamy if ((hal_rx_desc_sz + l3pad_bytes + msdu_len) > DP_RX_BUFFER_SIZE) 3940d5c65159SKalle Valo return -EINVAL; 3941d5c65159SKalle Valo 3942e678fbd4SKarthikeyan Periyasamy skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len); 3943e678fbd4SKarthikeyan Periyasamy skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes); 3944243874c6SManikanta Pubbisetty } 3945d5c65159SKalle Valo ath11k_dp_rx_h_ppdu(ar, desc, status); 3946d5c65159SKalle Valo 3947acc79d98SSriram R ath11k_dp_rx_h_mpdu(ar, msdu, desc, status); 3948d5c65159SKalle Valo 3949e678fbd4SKarthikeyan Periyasamy rxcb->tid = ath11k_dp_rx_h_mpdu_start_tid(ar->ab, desc); 3950d5c65159SKalle Valo 3951d5c65159SKalle Valo /* Please note that caller will having the access to msdu and completing 3952d5c65159SKalle Valo * rx with mac80211. Need not worry about cleaning up amsdu_list. 3953d5c65159SKalle Valo */ 3954d5c65159SKalle Valo 3955d5c65159SKalle Valo return 0; 3956d5c65159SKalle Valo } 3957d5c65159SKalle Valo 3958d5c65159SKalle Valo static bool ath11k_dp_rx_h_reo_err(struct ath11k *ar, struct sk_buff *msdu, 3959d5c65159SKalle Valo struct ieee80211_rx_status *status, 3960d5c65159SKalle Valo struct sk_buff_head *msdu_list) 3961d5c65159SKalle Valo { 3962d5c65159SKalle Valo struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 3963d5c65159SKalle Valo bool drop = false; 3964d5c65159SKalle Valo 3965d5c65159SKalle Valo ar->ab->soc_stats.reo_error[rxcb->err_code]++; 3966d5c65159SKalle Valo 3967d5c65159SKalle Valo switch (rxcb->err_code) { 3968d5c65159SKalle Valo case HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO: 3969d5c65159SKalle Valo if (ath11k_dp_rx_h_null_q_desc(ar, msdu, status, msdu_list)) 3970d5c65159SKalle Valo drop = true; 3971d5c65159SKalle Valo break; 39721441b2f2SManikanta Pubbisetty case HAL_REO_DEST_RING_ERROR_CODE_PN_CHECK_FAILED: 39731441b2f2SManikanta Pubbisetty /* TODO: Do not drop PN failed packets in the driver; 39741441b2f2SManikanta Pubbisetty * instead, it is good to drop such packets in mac80211 39751441b2f2SManikanta Pubbisetty * after incrementing the replay counters. 39761441b2f2SManikanta Pubbisetty */ 39770b294aebSGustavo A. R. Silva fallthrough; 3978d5c65159SKalle Valo default: 3979d5c65159SKalle Valo /* TODO: Review other errors and process them to mac80211 3980d5c65159SKalle Valo * as appropriate. 3981d5c65159SKalle Valo */ 3982d5c65159SKalle Valo drop = true; 3983d5c65159SKalle Valo break; 3984d5c65159SKalle Valo } 3985d5c65159SKalle Valo 3986d5c65159SKalle Valo return drop; 3987d5c65159SKalle Valo } 3988d5c65159SKalle Valo 3989d5c65159SKalle Valo static void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu, 3990d5c65159SKalle Valo struct ieee80211_rx_status *status) 3991d5c65159SKalle Valo { 3992d5c65159SKalle Valo u16 msdu_len; 3993d5c65159SKalle Valo struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data; 3994d5c65159SKalle Valo u8 l3pad_bytes; 3995d5c65159SKalle Valo struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 3996e678fbd4SKarthikeyan Periyasamy u32 hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz; 3997d5c65159SKalle Valo 3998e678fbd4SKarthikeyan Periyasamy rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(ar->ab, desc); 3999e678fbd4SKarthikeyan Periyasamy rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(ar->ab, desc); 4000d5c65159SKalle Valo 4001e678fbd4SKarthikeyan Periyasamy l3pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, desc); 4002e678fbd4SKarthikeyan Periyasamy msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(ar->ab, desc); 4003e678fbd4SKarthikeyan Periyasamy skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len); 4004e678fbd4SKarthikeyan Periyasamy skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes); 4005d5c65159SKalle Valo 4006d5c65159SKalle Valo ath11k_dp_rx_h_ppdu(ar, desc, status); 4007d5c65159SKalle Valo 4008d5c65159SKalle Valo status->flag |= (RX_FLAG_MMIC_STRIPPED | RX_FLAG_MMIC_ERROR | 4009d5c65159SKalle Valo RX_FLAG_DECRYPTED); 4010d5c65159SKalle Valo 4011d5c65159SKalle Valo ath11k_dp_rx_h_undecap(ar, msdu, desc, 4012d5c65159SKalle Valo HAL_ENCRYPT_TYPE_TKIP_MIC, status, false); 4013d5c65159SKalle Valo } 4014d5c65159SKalle Valo 4015d5c65159SKalle Valo static bool ath11k_dp_rx_h_rxdma_err(struct ath11k *ar, struct sk_buff *msdu, 4016d5c65159SKalle Valo struct ieee80211_rx_status *status) 4017d5c65159SKalle Valo { 4018d5c65159SKalle Valo struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 4019d5c65159SKalle Valo bool drop = false; 4020d5c65159SKalle Valo 4021d5c65159SKalle Valo ar->ab->soc_stats.rxdma_error[rxcb->err_code]++; 4022d5c65159SKalle Valo 4023d5c65159SKalle Valo switch (rxcb->err_code) { 4024d5c65159SKalle Valo case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR: 4025d5c65159SKalle Valo ath11k_dp_rx_h_tkip_mic_err(ar, msdu, status); 4026d5c65159SKalle Valo break; 4027d5c65159SKalle Valo default: 4028d5c65159SKalle Valo /* TODO: Review other rxdma error code to check if anything is 4029d5c65159SKalle Valo * worth reporting to mac80211 4030d5c65159SKalle Valo */ 4031d5c65159SKalle Valo drop = true; 4032d5c65159SKalle Valo break; 4033d5c65159SKalle Valo } 4034d5c65159SKalle Valo 4035d5c65159SKalle Valo return drop; 4036d5c65159SKalle Valo } 4037d5c65159SKalle Valo 4038d5c65159SKalle Valo static void ath11k_dp_rx_wbm_err(struct ath11k *ar, 4039d5c65159SKalle Valo struct napi_struct *napi, 4040d5c65159SKalle Valo struct sk_buff *msdu, 4041d5c65159SKalle Valo struct sk_buff_head *msdu_list) 4042d5c65159SKalle Valo { 4043d5c65159SKalle Valo struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 4044d5c65159SKalle Valo struct ieee80211_rx_status rxs = {0}; 4045d5c65159SKalle Valo bool drop = true; 4046d5c65159SKalle Valo 4047d5c65159SKalle Valo switch (rxcb->err_rel_src) { 4048d5c65159SKalle Valo case HAL_WBM_REL_SRC_MODULE_REO: 4049d5c65159SKalle Valo drop = ath11k_dp_rx_h_reo_err(ar, msdu, &rxs, msdu_list); 4050d5c65159SKalle Valo break; 4051d5c65159SKalle Valo case HAL_WBM_REL_SRC_MODULE_RXDMA: 4052d5c65159SKalle Valo drop = ath11k_dp_rx_h_rxdma_err(ar, msdu, &rxs); 4053d5c65159SKalle Valo break; 4054d5c65159SKalle Valo default: 4055d5c65159SKalle Valo /* msdu will get freed */ 4056d5c65159SKalle Valo break; 4057d5c65159SKalle Valo } 4058d5c65159SKalle Valo 4059d5c65159SKalle Valo if (drop) { 4060d5c65159SKalle Valo dev_kfree_skb_any(msdu); 4061d5c65159SKalle Valo return; 4062d5c65159SKalle Valo } 4063d5c65159SKalle Valo 40642167fa60SSriram R ath11k_dp_rx_deliver_msdu(ar, napi, msdu, &rxs); 4065d5c65159SKalle Valo } 4066d5c65159SKalle Valo 4067d5c65159SKalle Valo int ath11k_dp_rx_process_wbm_err(struct ath11k_base *ab, 4068d5c65159SKalle Valo struct napi_struct *napi, int budget) 4069d5c65159SKalle Valo { 4070d5c65159SKalle Valo struct ath11k *ar; 4071d5c65159SKalle Valo struct ath11k_dp *dp = &ab->dp; 4072d5c65159SKalle Valo struct dp_rxdma_ring *rx_ring; 4073d5c65159SKalle Valo struct hal_rx_wbm_rel_info err_info; 4074d5c65159SKalle Valo struct hal_srng *srng; 4075d5c65159SKalle Valo struct sk_buff *msdu; 4076d5c65159SKalle Valo struct sk_buff_head msdu_list[MAX_RADIOS]; 4077d5c65159SKalle Valo struct ath11k_skb_rxcb *rxcb; 4078d5c65159SKalle Valo u32 *rx_desc; 4079d5c65159SKalle Valo int buf_id, mac_id; 4080d5c65159SKalle Valo int num_buffs_reaped[MAX_RADIOS] = {0}; 4081d5c65159SKalle Valo int total_num_buffs_reaped = 0; 4082d5c65159SKalle Valo int ret, i; 4083d5c65159SKalle Valo 4084b1cc29e9SAnilkumar Kolli for (i = 0; i < ab->num_radios; i++) 4085d5c65159SKalle Valo __skb_queue_head_init(&msdu_list[i]); 4086d5c65159SKalle Valo 4087d5c65159SKalle Valo srng = &ab->hal.srng_list[dp->rx_rel_ring.ring_id]; 4088d5c65159SKalle Valo 4089d5c65159SKalle Valo spin_lock_bh(&srng->lock); 4090d5c65159SKalle Valo 4091d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 4092d5c65159SKalle Valo 4093d5c65159SKalle Valo while (budget) { 4094d5c65159SKalle Valo rx_desc = ath11k_hal_srng_dst_get_next_entry(ab, srng); 4095d5c65159SKalle Valo if (!rx_desc) 4096d5c65159SKalle Valo break; 4097d5c65159SKalle Valo 4098d5c65159SKalle Valo ret = ath11k_hal_wbm_desc_parse_err(ab, rx_desc, &err_info); 4099d5c65159SKalle Valo if (ret) { 4100d5c65159SKalle Valo ath11k_warn(ab, 4101d5c65159SKalle Valo "failed to parse rx error in wbm_rel ring desc %d\n", 4102d5c65159SKalle Valo ret); 4103d5c65159SKalle Valo continue; 4104d5c65159SKalle Valo } 4105d5c65159SKalle Valo 4106d5c65159SKalle Valo buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, err_info.cookie); 4107d5c65159SKalle Valo mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, err_info.cookie); 4108d5c65159SKalle Valo 4109d5c65159SKalle Valo ar = ab->pdevs[mac_id].ar; 4110d5c65159SKalle Valo rx_ring = &ar->dp.rx_refill_buf_ring; 4111d5c65159SKalle Valo 4112d5c65159SKalle Valo spin_lock_bh(&rx_ring->idr_lock); 4113d5c65159SKalle Valo msdu = idr_find(&rx_ring->bufs_idr, buf_id); 4114d5c65159SKalle Valo if (!msdu) { 4115d5c65159SKalle Valo ath11k_warn(ab, "frame rx with invalid buf_id %d pdev %d\n", 4116d5c65159SKalle Valo buf_id, mac_id); 4117d5c65159SKalle Valo spin_unlock_bh(&rx_ring->idr_lock); 4118d5c65159SKalle Valo continue; 4119d5c65159SKalle Valo } 4120d5c65159SKalle Valo 4121d5c65159SKalle Valo idr_remove(&rx_ring->bufs_idr, buf_id); 4122d5c65159SKalle Valo spin_unlock_bh(&rx_ring->idr_lock); 4123d5c65159SKalle Valo 4124d5c65159SKalle Valo rxcb = ATH11K_SKB_RXCB(msdu); 4125d5c65159SKalle Valo dma_unmap_single(ab->dev, rxcb->paddr, 4126d5c65159SKalle Valo msdu->len + skb_tailroom(msdu), 4127d5c65159SKalle Valo DMA_FROM_DEVICE); 4128d5c65159SKalle Valo 4129d5c65159SKalle Valo num_buffs_reaped[mac_id]++; 4130d5c65159SKalle Valo total_num_buffs_reaped++; 4131d5c65159SKalle Valo budget--; 4132d5c65159SKalle Valo 4133d5c65159SKalle Valo if (err_info.push_reason != 4134d5c65159SKalle Valo HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED) { 4135d5c65159SKalle Valo dev_kfree_skb_any(msdu); 4136d5c65159SKalle Valo continue; 4137d5c65159SKalle Valo } 4138d5c65159SKalle Valo 4139d5c65159SKalle Valo rxcb->err_rel_src = err_info.err_rel_src; 4140d5c65159SKalle Valo rxcb->err_code = err_info.err_code; 4141d5c65159SKalle Valo rxcb->rx_desc = (struct hal_rx_desc *)msdu->data; 4142d5c65159SKalle Valo __skb_queue_tail(&msdu_list[mac_id], msdu); 4143d5c65159SKalle Valo } 4144d5c65159SKalle Valo 4145d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 4146d5c65159SKalle Valo 4147d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 4148d5c65159SKalle Valo 4149d5c65159SKalle Valo if (!total_num_buffs_reaped) 4150d5c65159SKalle Valo goto done; 4151d5c65159SKalle Valo 4152d5c65159SKalle Valo for (i = 0; i < ab->num_radios; i++) { 4153d5c65159SKalle Valo if (!num_buffs_reaped[i]) 4154d5c65159SKalle Valo continue; 4155d5c65159SKalle Valo 4156d5c65159SKalle Valo ar = ab->pdevs[i].ar; 4157d5c65159SKalle Valo rx_ring = &ar->dp.rx_refill_buf_ring; 4158d5c65159SKalle Valo 4159d5c65159SKalle Valo ath11k_dp_rxbufs_replenish(ab, i, rx_ring, num_buffs_reaped[i], 4160734223d7SBaochen Qiang ab->hw_params.hal_params->rx_buf_rbm); 4161d5c65159SKalle Valo } 4162d5c65159SKalle Valo 4163d5c65159SKalle Valo rcu_read_lock(); 4164d5c65159SKalle Valo for (i = 0; i < ab->num_radios; i++) { 4165d5c65159SKalle Valo if (!rcu_dereference(ab->pdevs_active[i])) { 4166d5c65159SKalle Valo __skb_queue_purge(&msdu_list[i]); 4167d5c65159SKalle Valo continue; 4168d5c65159SKalle Valo } 4169d5c65159SKalle Valo 4170d5c65159SKalle Valo ar = ab->pdevs[i].ar; 4171d5c65159SKalle Valo 4172d5c65159SKalle Valo if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) { 4173d5c65159SKalle Valo __skb_queue_purge(&msdu_list[i]); 4174d5c65159SKalle Valo continue; 4175d5c65159SKalle Valo } 4176d5c65159SKalle Valo 4177d5c65159SKalle Valo while ((msdu = __skb_dequeue(&msdu_list[i])) != NULL) 4178d5c65159SKalle Valo ath11k_dp_rx_wbm_err(ar, napi, msdu, &msdu_list[i]); 4179d5c65159SKalle Valo } 4180d5c65159SKalle Valo rcu_read_unlock(); 4181d5c65159SKalle Valo done: 4182d5c65159SKalle Valo return total_num_buffs_reaped; 4183d5c65159SKalle Valo } 4184d5c65159SKalle Valo 4185d5c65159SKalle Valo int ath11k_dp_process_rxdma_err(struct ath11k_base *ab, int mac_id, int budget) 4186d5c65159SKalle Valo { 41874152e420SCarl Huang struct ath11k *ar; 41884152e420SCarl Huang struct dp_srng *err_ring; 41894152e420SCarl Huang struct dp_rxdma_ring *rx_ring; 4190d5c65159SKalle Valo struct dp_link_desc_bank *link_desc_banks = ab->dp.link_desc_banks; 4191d5c65159SKalle Valo struct hal_srng *srng; 4192293cb583SJohn Crispin u32 msdu_cookies[HAL_NUM_RX_MSDUS_PER_LINK_DESC]; 4193d5c65159SKalle Valo enum hal_rx_buf_return_buf_manager rbm; 4194d5c65159SKalle Valo enum hal_reo_entr_rxdma_ecode rxdma_err_code; 4195d5c65159SKalle Valo struct ath11k_skb_rxcb *rxcb; 4196d5c65159SKalle Valo struct sk_buff *skb; 4197d5c65159SKalle Valo struct hal_reo_entrance_ring *entr_ring; 4198d5c65159SKalle Valo void *desc; 4199d5c65159SKalle Valo int num_buf_freed = 0; 4200d5c65159SKalle Valo int quota = budget; 4201d5c65159SKalle Valo dma_addr_t paddr; 4202d5c65159SKalle Valo u32 desc_bank; 4203d5c65159SKalle Valo void *link_desc_va; 4204d5c65159SKalle Valo int num_msdus; 4205d5c65159SKalle Valo int i; 4206d5c65159SKalle Valo int buf_id; 4207d5c65159SKalle Valo 42084152e420SCarl Huang ar = ab->pdevs[ath11k_hw_mac_id_to_pdev_id(&ab->hw_params, mac_id)].ar; 42094152e420SCarl Huang err_ring = &ar->dp.rxdma_err_dst_ring[ath11k_hw_mac_id_to_srng_id(&ab->hw_params, 42104152e420SCarl Huang mac_id)]; 42114152e420SCarl Huang rx_ring = &ar->dp.rx_refill_buf_ring; 42124152e420SCarl Huang 4213d5c65159SKalle Valo srng = &ab->hal.srng_list[err_ring->ring_id]; 4214d5c65159SKalle Valo 4215d5c65159SKalle Valo spin_lock_bh(&srng->lock); 4216d5c65159SKalle Valo 4217d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 4218d5c65159SKalle Valo 4219d5c65159SKalle Valo while (quota-- && 4220d5c65159SKalle Valo (desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) { 4221d5c65159SKalle Valo ath11k_hal_rx_reo_ent_paddr_get(ab, desc, &paddr, &desc_bank); 4222d5c65159SKalle Valo 4223d5c65159SKalle Valo entr_ring = (struct hal_reo_entrance_ring *)desc; 4224d5c65159SKalle Valo rxdma_err_code = 4225d5c65159SKalle Valo FIELD_GET(HAL_REO_ENTR_RING_INFO1_RXDMA_ERROR_CODE, 4226d5c65159SKalle Valo entr_ring->info1); 4227d5c65159SKalle Valo ab->soc_stats.rxdma_error[rxdma_err_code]++; 4228d5c65159SKalle Valo 4229d5c65159SKalle Valo link_desc_va = link_desc_banks[desc_bank].vaddr + 4230d5c65159SKalle Valo (paddr - link_desc_banks[desc_bank].paddr); 4231293cb583SJohn Crispin ath11k_hal_rx_msdu_link_info_get(link_desc_va, &num_msdus, 4232293cb583SJohn Crispin msdu_cookies, &rbm); 4233d5c65159SKalle Valo 4234d5c65159SKalle Valo for (i = 0; i < num_msdus; i++) { 4235d5c65159SKalle Valo buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, 4236293cb583SJohn Crispin msdu_cookies[i]); 4237d5c65159SKalle Valo 4238d5c65159SKalle Valo spin_lock_bh(&rx_ring->idr_lock); 4239d5c65159SKalle Valo skb = idr_find(&rx_ring->bufs_idr, buf_id); 4240d5c65159SKalle Valo if (!skb) { 4241d5c65159SKalle Valo ath11k_warn(ab, "rxdma error with invalid buf_id %d\n", 4242d5c65159SKalle Valo buf_id); 4243d5c65159SKalle Valo spin_unlock_bh(&rx_ring->idr_lock); 4244d5c65159SKalle Valo continue; 4245d5c65159SKalle Valo } 4246d5c65159SKalle Valo 4247d5c65159SKalle Valo idr_remove(&rx_ring->bufs_idr, buf_id); 4248d5c65159SKalle Valo spin_unlock_bh(&rx_ring->idr_lock); 4249d5c65159SKalle Valo 4250d5c65159SKalle Valo rxcb = ATH11K_SKB_RXCB(skb); 4251d5c65159SKalle Valo dma_unmap_single(ab->dev, rxcb->paddr, 4252d5c65159SKalle Valo skb->len + skb_tailroom(skb), 4253d5c65159SKalle Valo DMA_FROM_DEVICE); 4254d5c65159SKalle Valo dev_kfree_skb_any(skb); 4255d5c65159SKalle Valo 4256d5c65159SKalle Valo num_buf_freed++; 4257d5c65159SKalle Valo } 4258d5c65159SKalle Valo 4259d5c65159SKalle Valo ath11k_dp_rx_link_desc_return(ab, desc, 4260d5c65159SKalle Valo HAL_WBM_REL_BM_ACT_PUT_IN_IDLE); 4261d5c65159SKalle Valo } 4262d5c65159SKalle Valo 4263d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 4264d5c65159SKalle Valo 4265d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 4266d5c65159SKalle Valo 4267d5c65159SKalle Valo if (num_buf_freed) 4268d5c65159SKalle Valo ath11k_dp_rxbufs_replenish(ab, mac_id, rx_ring, num_buf_freed, 4269734223d7SBaochen Qiang ab->hw_params.hal_params->rx_buf_rbm); 4270d5c65159SKalle Valo 4271d5c65159SKalle Valo return budget - quota; 4272d5c65159SKalle Valo } 4273d5c65159SKalle Valo 4274d5c65159SKalle Valo void ath11k_dp_process_reo_status(struct ath11k_base *ab) 4275d5c65159SKalle Valo { 4276d5c65159SKalle Valo struct ath11k_dp *dp = &ab->dp; 4277d5c65159SKalle Valo struct hal_srng *srng; 4278d5c65159SKalle Valo struct dp_reo_cmd *cmd, *tmp; 4279d5c65159SKalle Valo bool found = false; 4280d5c65159SKalle Valo u32 *reo_desc; 4281d5c65159SKalle Valo u16 tag; 4282d5c65159SKalle Valo struct hal_reo_status reo_status; 4283d5c65159SKalle Valo 4284d5c65159SKalle Valo srng = &ab->hal.srng_list[dp->reo_status_ring.ring_id]; 4285d5c65159SKalle Valo 4286d5c65159SKalle Valo memset(&reo_status, 0, sizeof(reo_status)); 4287d5c65159SKalle Valo 4288d5c65159SKalle Valo spin_lock_bh(&srng->lock); 4289d5c65159SKalle Valo 4290d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 4291d5c65159SKalle Valo 4292d5c65159SKalle Valo while ((reo_desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) { 4293d5c65159SKalle Valo tag = FIELD_GET(HAL_SRNG_TLV_HDR_TAG, *reo_desc); 4294d5c65159SKalle Valo 4295d5c65159SKalle Valo switch (tag) { 4296d5c65159SKalle Valo case HAL_REO_GET_QUEUE_STATS_STATUS: 4297d5c65159SKalle Valo ath11k_hal_reo_status_queue_stats(ab, reo_desc, 4298d5c65159SKalle Valo &reo_status); 4299d5c65159SKalle Valo break; 4300d5c65159SKalle Valo case HAL_REO_FLUSH_QUEUE_STATUS: 4301d5c65159SKalle Valo ath11k_hal_reo_flush_queue_status(ab, reo_desc, 4302d5c65159SKalle Valo &reo_status); 4303d5c65159SKalle Valo break; 4304d5c65159SKalle Valo case HAL_REO_FLUSH_CACHE_STATUS: 4305d5c65159SKalle Valo ath11k_hal_reo_flush_cache_status(ab, reo_desc, 4306d5c65159SKalle Valo &reo_status); 4307d5c65159SKalle Valo break; 4308d5c65159SKalle Valo case HAL_REO_UNBLOCK_CACHE_STATUS: 4309d5c65159SKalle Valo ath11k_hal_reo_unblk_cache_status(ab, reo_desc, 4310d5c65159SKalle Valo &reo_status); 4311d5c65159SKalle Valo break; 4312d5c65159SKalle Valo case HAL_REO_FLUSH_TIMEOUT_LIST_STATUS: 4313d5c65159SKalle Valo ath11k_hal_reo_flush_timeout_list_status(ab, reo_desc, 4314d5c65159SKalle Valo &reo_status); 4315d5c65159SKalle Valo break; 4316d5c65159SKalle Valo case HAL_REO_DESCRIPTOR_THRESHOLD_REACHED_STATUS: 4317d5c65159SKalle Valo ath11k_hal_reo_desc_thresh_reached_status(ab, reo_desc, 4318d5c65159SKalle Valo &reo_status); 4319d5c65159SKalle Valo break; 4320d5c65159SKalle Valo case HAL_REO_UPDATE_RX_REO_QUEUE_STATUS: 4321d5c65159SKalle Valo ath11k_hal_reo_update_rx_reo_queue_status(ab, reo_desc, 4322d5c65159SKalle Valo &reo_status); 4323d5c65159SKalle Valo break; 4324d5c65159SKalle Valo default: 4325d5c65159SKalle Valo ath11k_warn(ab, "Unknown reo status type %d\n", tag); 4326d5c65159SKalle Valo continue; 4327d5c65159SKalle Valo } 4328d5c65159SKalle Valo 4329d5c65159SKalle Valo spin_lock_bh(&dp->reo_cmd_lock); 4330d5c65159SKalle Valo list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) { 4331d5c65159SKalle Valo if (reo_status.uniform_hdr.cmd_num == cmd->cmd_num) { 4332d5c65159SKalle Valo found = true; 4333d5c65159SKalle Valo list_del(&cmd->list); 4334d5c65159SKalle Valo break; 4335d5c65159SKalle Valo } 4336d5c65159SKalle Valo } 4337d5c65159SKalle Valo spin_unlock_bh(&dp->reo_cmd_lock); 4338d5c65159SKalle Valo 4339d5c65159SKalle Valo if (found) { 4340d5c65159SKalle Valo cmd->handler(dp, (void *)&cmd->data, 4341d5c65159SKalle Valo reo_status.uniform_hdr.cmd_status); 4342d5c65159SKalle Valo kfree(cmd); 4343d5c65159SKalle Valo } 4344d5c65159SKalle Valo 4345d5c65159SKalle Valo found = false; 4346d5c65159SKalle Valo } 4347d5c65159SKalle Valo 4348d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 4349d5c65159SKalle Valo 4350d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 4351d5c65159SKalle Valo } 4352d5c65159SKalle Valo 4353d5c65159SKalle Valo void ath11k_dp_rx_pdev_free(struct ath11k_base *ab, int mac_id) 4354d5c65159SKalle Valo { 4355d5c65159SKalle Valo struct ath11k *ar = ab->pdevs[mac_id].ar; 4356d5c65159SKalle Valo 4357d5c65159SKalle Valo ath11k_dp_rx_pdev_srng_free(ar); 4358d5c65159SKalle Valo ath11k_dp_rxdma_pdev_buf_free(ar); 4359d5c65159SKalle Valo } 4360d5c65159SKalle Valo 4361d5c65159SKalle Valo int ath11k_dp_rx_pdev_alloc(struct ath11k_base *ab, int mac_id) 4362d5c65159SKalle Valo { 4363d5c65159SKalle Valo struct ath11k *ar = ab->pdevs[mac_id].ar; 4364d5c65159SKalle Valo struct ath11k_pdev_dp *dp = &ar->dp; 4365d5c65159SKalle Valo u32 ring_id; 43664152e420SCarl Huang int i; 4367d5c65159SKalle Valo int ret; 4368d5c65159SKalle Valo 4369d5c65159SKalle Valo ret = ath11k_dp_rx_pdev_srng_alloc(ar); 4370d5c65159SKalle Valo if (ret) { 4371d5c65159SKalle Valo ath11k_warn(ab, "failed to setup rx srngs\n"); 4372d5c65159SKalle Valo return ret; 4373d5c65159SKalle Valo } 4374d5c65159SKalle Valo 4375d5c65159SKalle Valo ret = ath11k_dp_rxdma_pdev_buf_setup(ar); 4376d5c65159SKalle Valo if (ret) { 4377d5c65159SKalle Valo ath11k_warn(ab, "failed to setup rxdma ring\n"); 4378d5c65159SKalle Valo return ret; 4379d5c65159SKalle Valo } 4380d5c65159SKalle Valo 4381d5c65159SKalle Valo ring_id = dp->rx_refill_buf_ring.refill_buf_ring.ring_id; 4382d5c65159SKalle Valo ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id, HAL_RXDMA_BUF); 4383d5c65159SKalle Valo if (ret) { 4384d5c65159SKalle Valo ath11k_warn(ab, "failed to configure rx_refill_buf_ring %d\n", 4385d5c65159SKalle Valo ret); 4386d5c65159SKalle Valo return ret; 4387d5c65159SKalle Valo } 4388d5c65159SKalle Valo 43894152e420SCarl Huang if (ab->hw_params.rx_mac_buf_ring) { 43904152e420SCarl Huang for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { 43914152e420SCarl Huang ring_id = dp->rx_mac_buf_ring[i].ring_id; 43924152e420SCarl Huang ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, 43934152e420SCarl Huang mac_id + i, HAL_RXDMA_BUF); 4394d5c65159SKalle Valo if (ret) { 43954152e420SCarl Huang ath11k_warn(ab, "failed to configure rx_mac_buf_ring%d %d\n", 43964152e420SCarl Huang i, ret); 4397d5c65159SKalle Valo return ret; 4398d5c65159SKalle Valo } 43994152e420SCarl Huang } 44004152e420SCarl Huang } 44014152e420SCarl Huang 44024152e420SCarl Huang for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { 44034152e420SCarl Huang ring_id = dp->rxdma_err_dst_ring[i].ring_id; 44044152e420SCarl Huang ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, 44054152e420SCarl Huang mac_id + i, HAL_RXDMA_DST); 44064152e420SCarl Huang if (ret) { 44074152e420SCarl Huang ath11k_warn(ab, "failed to configure rxdma_err_dest_ring%d %d\n", 44084152e420SCarl Huang i, ret); 44094152e420SCarl Huang return ret; 44104152e420SCarl Huang } 44114152e420SCarl Huang } 4412d5c65159SKalle Valo 44137f6fc1ebSCarl Huang if (!ab->hw_params.rxdma1_enable) 44147f6fc1ebSCarl Huang goto config_refill_ring; 44157f6fc1ebSCarl Huang 4416d5c65159SKalle Valo ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id; 4417d5c65159SKalle Valo ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, 4418d5c65159SKalle Valo mac_id, HAL_RXDMA_MONITOR_BUF); 4419d5c65159SKalle Valo if (ret) { 4420d5c65159SKalle Valo ath11k_warn(ab, "failed to configure rxdma_mon_buf_ring %d\n", 4421d5c65159SKalle Valo ret); 4422d5c65159SKalle Valo return ret; 4423d5c65159SKalle Valo } 4424d5c65159SKalle Valo ret = ath11k_dp_tx_htt_srng_setup(ab, 4425d5c65159SKalle Valo dp->rxdma_mon_dst_ring.ring_id, 4426d5c65159SKalle Valo mac_id, HAL_RXDMA_MONITOR_DST); 4427d5c65159SKalle Valo if (ret) { 4428d5c65159SKalle Valo ath11k_warn(ab, "failed to configure rxdma_mon_dst_ring %d\n", 4429d5c65159SKalle Valo ret); 4430d5c65159SKalle Valo return ret; 4431d5c65159SKalle Valo } 4432d5c65159SKalle Valo ret = ath11k_dp_tx_htt_srng_setup(ab, 4433d5c65159SKalle Valo dp->rxdma_mon_desc_ring.ring_id, 4434d5c65159SKalle Valo mac_id, HAL_RXDMA_MONITOR_DESC); 4435d5c65159SKalle Valo if (ret) { 4436d5c65159SKalle Valo ath11k_warn(ab, "failed to configure rxdma_mon_dst_ring %d\n", 4437d5c65159SKalle Valo ret); 4438d5c65159SKalle Valo return ret; 4439d5c65159SKalle Valo } 44407f6fc1ebSCarl Huang 44417f6fc1ebSCarl Huang config_refill_ring: 44424152e420SCarl Huang for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { 44434152e420SCarl Huang ring_id = dp->rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; 44444152e420SCarl Huang ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id + i, 4445d5c65159SKalle Valo HAL_RXDMA_MONITOR_STATUS); 4446d5c65159SKalle Valo if (ret) { 4447d5c65159SKalle Valo ath11k_warn(ab, 44484152e420SCarl Huang "failed to configure mon_status_refill_ring%d %d\n", 44494152e420SCarl Huang i, ret); 4450d5c65159SKalle Valo return ret; 4451d5c65159SKalle Valo } 44524152e420SCarl Huang } 44537f6fc1ebSCarl Huang 4454d5c65159SKalle Valo return 0; 4455d5c65159SKalle Valo } 4456d5c65159SKalle Valo 4457d5c65159SKalle Valo static void ath11k_dp_mon_set_frag_len(u32 *total_len, u32 *frag_len) 4458d5c65159SKalle Valo { 4459d5c65159SKalle Valo if (*total_len >= (DP_RX_BUFFER_SIZE - sizeof(struct hal_rx_desc))) { 4460d5c65159SKalle Valo *frag_len = DP_RX_BUFFER_SIZE - sizeof(struct hal_rx_desc); 4461d5c65159SKalle Valo *total_len -= *frag_len; 4462d5c65159SKalle Valo } else { 4463d5c65159SKalle Valo *frag_len = *total_len; 4464d5c65159SKalle Valo *total_len = 0; 4465d5c65159SKalle Valo } 4466d5c65159SKalle Valo } 4467d5c65159SKalle Valo 4468d5c65159SKalle Valo static 4469d5c65159SKalle Valo int ath11k_dp_rx_monitor_link_desc_return(struct ath11k *ar, 4470d5c65159SKalle Valo void *p_last_buf_addr_info, 4471d5c65159SKalle Valo u8 mac_id) 4472d5c65159SKalle Valo { 4473d5c65159SKalle Valo struct ath11k_pdev_dp *dp = &ar->dp; 4474d5c65159SKalle Valo struct dp_srng *dp_srng; 4475d5c65159SKalle Valo void *hal_srng; 4476d5c65159SKalle Valo void *src_srng_desc; 4477d5c65159SKalle Valo int ret = 0; 4478d5c65159SKalle Valo 4479701e48a4SCarl Huang if (ar->ab->hw_params.rxdma1_enable) { 4480d5c65159SKalle Valo dp_srng = &dp->rxdma_mon_desc_ring; 4481d5c65159SKalle Valo hal_srng = &ar->ab->hal.srng_list[dp_srng->ring_id]; 4482701e48a4SCarl Huang } else { 4483701e48a4SCarl Huang dp_srng = &ar->ab->dp.wbm_desc_rel_ring; 4484701e48a4SCarl Huang hal_srng = &ar->ab->hal.srng_list[dp_srng->ring_id]; 4485701e48a4SCarl Huang } 4486d5c65159SKalle Valo 4487d5c65159SKalle Valo ath11k_hal_srng_access_begin(ar->ab, hal_srng); 4488d5c65159SKalle Valo 4489d5c65159SKalle Valo src_srng_desc = ath11k_hal_srng_src_get_next_entry(ar->ab, hal_srng); 4490d5c65159SKalle Valo 4491d5c65159SKalle Valo if (src_srng_desc) { 4492d5c65159SKalle Valo struct ath11k_buffer_addr *src_desc = 4493d5c65159SKalle Valo (struct ath11k_buffer_addr *)src_srng_desc; 4494d5c65159SKalle Valo 4495d5c65159SKalle Valo *src_desc = *((struct ath11k_buffer_addr *)p_last_buf_addr_info); 4496d5c65159SKalle Valo } else { 4497d5c65159SKalle Valo ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 4498d5c65159SKalle Valo "Monitor Link Desc Ring %d Full", mac_id); 4499d5c65159SKalle Valo ret = -ENOMEM; 4500d5c65159SKalle Valo } 4501d5c65159SKalle Valo 4502d5c65159SKalle Valo ath11k_hal_srng_access_end(ar->ab, hal_srng); 4503d5c65159SKalle Valo return ret; 4504d5c65159SKalle Valo } 4505d5c65159SKalle Valo 4506d5c65159SKalle Valo static 4507d5c65159SKalle Valo void ath11k_dp_rx_mon_next_link_desc_get(void *rx_msdu_link_desc, 4508d5c65159SKalle Valo dma_addr_t *paddr, u32 *sw_cookie, 4509701e48a4SCarl Huang u8 *rbm, 4510d5c65159SKalle Valo void **pp_buf_addr_info) 4511d5c65159SKalle Valo { 4512d5c65159SKalle Valo struct hal_rx_msdu_link *msdu_link = 4513d5c65159SKalle Valo (struct hal_rx_msdu_link *)rx_msdu_link_desc; 4514d5c65159SKalle Valo struct ath11k_buffer_addr *buf_addr_info; 4515d5c65159SKalle Valo 4516d5c65159SKalle Valo buf_addr_info = (struct ath11k_buffer_addr *)&msdu_link->buf_addr_info; 4517d5c65159SKalle Valo 4518701e48a4SCarl Huang ath11k_hal_rx_buf_addr_info_get(buf_addr_info, paddr, sw_cookie, rbm); 4519d5c65159SKalle Valo 4520d5c65159SKalle Valo *pp_buf_addr_info = (void *)buf_addr_info; 4521d5c65159SKalle Valo } 4522d5c65159SKalle Valo 4523d5c65159SKalle Valo static int ath11k_dp_pkt_set_pktlen(struct sk_buff *skb, u32 len) 4524d5c65159SKalle Valo { 4525d5c65159SKalle Valo if (skb->len > len) { 4526d5c65159SKalle Valo skb_trim(skb, len); 4527d5c65159SKalle Valo } else { 4528d5c65159SKalle Valo if (skb_tailroom(skb) < len - skb->len) { 4529d5c65159SKalle Valo if ((pskb_expand_head(skb, 0, 4530d5c65159SKalle Valo len - skb->len - skb_tailroom(skb), 4531d5c65159SKalle Valo GFP_ATOMIC))) { 4532d5c65159SKalle Valo dev_kfree_skb_any(skb); 4533d5c65159SKalle Valo return -ENOMEM; 4534d5c65159SKalle Valo } 4535d5c65159SKalle Valo } 4536d5c65159SKalle Valo skb_put(skb, (len - skb->len)); 4537d5c65159SKalle Valo } 4538d5c65159SKalle Valo return 0; 4539d5c65159SKalle Valo } 4540d5c65159SKalle Valo 4541d5c65159SKalle Valo static void ath11k_hal_rx_msdu_list_get(struct ath11k *ar, 4542d5c65159SKalle Valo void *msdu_link_desc, 4543d5c65159SKalle Valo struct hal_rx_msdu_list *msdu_list, 4544d5c65159SKalle Valo u16 *num_msdus) 4545d5c65159SKalle Valo { 4546d5c65159SKalle Valo struct hal_rx_msdu_details *msdu_details = NULL; 4547d5c65159SKalle Valo struct rx_msdu_desc *msdu_desc_info = NULL; 4548d5c65159SKalle Valo struct hal_rx_msdu_link *msdu_link = NULL; 4549d5c65159SKalle Valo int i; 4550d5c65159SKalle Valo u32 last = FIELD_PREP(RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU, 1); 4551d5c65159SKalle Valo u32 first = FIELD_PREP(RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU, 1); 4552d5c65159SKalle Valo u8 tmp = 0; 4553d5c65159SKalle Valo 4554d5c65159SKalle Valo msdu_link = (struct hal_rx_msdu_link *)msdu_link_desc; 4555d5c65159SKalle Valo msdu_details = &msdu_link->msdu_link[0]; 4556d5c65159SKalle Valo 4557d5c65159SKalle Valo for (i = 0; i < HAL_RX_NUM_MSDU_DESC; i++) { 4558d5c65159SKalle Valo if (FIELD_GET(BUFFER_ADDR_INFO0_ADDR, 4559d5c65159SKalle Valo msdu_details[i].buf_addr_info.info0) == 0) { 4560d5c65159SKalle Valo msdu_desc_info = &msdu_details[i - 1].rx_msdu_info; 4561d5c65159SKalle Valo msdu_desc_info->info0 |= last; 4562d5c65159SKalle Valo ; 4563d5c65159SKalle Valo break; 4564d5c65159SKalle Valo } 4565d5c65159SKalle Valo msdu_desc_info = &msdu_details[i].rx_msdu_info; 4566d5c65159SKalle Valo 4567d5c65159SKalle Valo if (!i) 4568d5c65159SKalle Valo msdu_desc_info->info0 |= first; 4569d5c65159SKalle Valo else if (i == (HAL_RX_NUM_MSDU_DESC - 1)) 4570d5c65159SKalle Valo msdu_desc_info->info0 |= last; 4571d5c65159SKalle Valo msdu_list->msdu_info[i].msdu_flags = msdu_desc_info->info0; 4572d5c65159SKalle Valo msdu_list->msdu_info[i].msdu_len = 4573d5c65159SKalle Valo HAL_RX_MSDU_PKT_LENGTH_GET(msdu_desc_info->info0); 4574d5c65159SKalle Valo msdu_list->sw_cookie[i] = 4575d5c65159SKalle Valo FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, 4576d5c65159SKalle Valo msdu_details[i].buf_addr_info.info1); 4577d5c65159SKalle Valo tmp = FIELD_GET(BUFFER_ADDR_INFO1_RET_BUF_MGR, 4578d5c65159SKalle Valo msdu_details[i].buf_addr_info.info1); 4579d5c65159SKalle Valo msdu_list->rbm[i] = tmp; 4580d5c65159SKalle Valo } 4581d5c65159SKalle Valo *num_msdus = i; 4582d5c65159SKalle Valo } 4583d5c65159SKalle Valo 4584d5c65159SKalle Valo static u32 ath11k_dp_rx_mon_comp_ppduid(u32 msdu_ppdu_id, u32 *ppdu_id, 4585d5c65159SKalle Valo u32 *rx_bufs_used) 4586d5c65159SKalle Valo { 4587d5c65159SKalle Valo u32 ret = 0; 4588d5c65159SKalle Valo 4589d5c65159SKalle Valo if ((*ppdu_id < msdu_ppdu_id) && 4590d5c65159SKalle Valo ((msdu_ppdu_id - *ppdu_id) < DP_NOT_PPDU_ID_WRAP_AROUND)) { 4591d5c65159SKalle Valo *ppdu_id = msdu_ppdu_id; 4592d5c65159SKalle Valo ret = msdu_ppdu_id; 4593d5c65159SKalle Valo } else if ((*ppdu_id > msdu_ppdu_id) && 4594d5c65159SKalle Valo ((*ppdu_id - msdu_ppdu_id) > DP_NOT_PPDU_ID_WRAP_AROUND)) { 4595d5c65159SKalle Valo /* mon_dst is behind than mon_status 4596d5c65159SKalle Valo * skip dst_ring and free it 4597d5c65159SKalle Valo */ 4598d5c65159SKalle Valo *rx_bufs_used += 1; 4599d5c65159SKalle Valo *ppdu_id = msdu_ppdu_id; 4600d5c65159SKalle Valo ret = msdu_ppdu_id; 4601d5c65159SKalle Valo } 4602d5c65159SKalle Valo return ret; 4603d5c65159SKalle Valo } 4604d5c65159SKalle Valo 4605d5c65159SKalle Valo static void ath11k_dp_mon_get_buf_len(struct hal_rx_msdu_desc_info *info, 4606d5c65159SKalle Valo bool *is_frag, u32 *total_len, 4607d5c65159SKalle Valo u32 *frag_len, u32 *msdu_cnt) 4608d5c65159SKalle Valo { 4609d5c65159SKalle Valo if (info->msdu_flags & RX_MSDU_DESC_INFO0_MSDU_CONTINUATION) { 4610d5c65159SKalle Valo if (!*is_frag) { 4611d5c65159SKalle Valo *total_len = info->msdu_len; 4612d5c65159SKalle Valo *is_frag = true; 4613d5c65159SKalle Valo } 4614d5c65159SKalle Valo ath11k_dp_mon_set_frag_len(total_len, 4615d5c65159SKalle Valo frag_len); 4616d5c65159SKalle Valo } else { 4617d5c65159SKalle Valo if (*is_frag) { 4618d5c65159SKalle Valo ath11k_dp_mon_set_frag_len(total_len, 4619d5c65159SKalle Valo frag_len); 4620d5c65159SKalle Valo } else { 4621d5c65159SKalle Valo *frag_len = info->msdu_len; 4622d5c65159SKalle Valo } 4623d5c65159SKalle Valo *is_frag = false; 4624d5c65159SKalle Valo *msdu_cnt -= 1; 4625d5c65159SKalle Valo } 4626d5c65159SKalle Valo } 4627d5c65159SKalle Valo 4628d5c65159SKalle Valo static u32 4629701e48a4SCarl Huang ath11k_dp_rx_mon_mpdu_pop(struct ath11k *ar, int mac_id, 4630d5c65159SKalle Valo void *ring_entry, struct sk_buff **head_msdu, 4631d5c65159SKalle Valo struct sk_buff **tail_msdu, u32 *npackets, 4632d5c65159SKalle Valo u32 *ppdu_id) 4633d5c65159SKalle Valo { 4634d5c65159SKalle Valo struct ath11k_pdev_dp *dp = &ar->dp; 4635d5c65159SKalle Valo struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data; 4636d5c65159SKalle Valo struct dp_rxdma_ring *rx_ring = &dp->rxdma_mon_buf_ring; 4637d5c65159SKalle Valo struct sk_buff *msdu = NULL, *last = NULL; 4638d5c65159SKalle Valo struct hal_rx_msdu_list msdu_list; 4639d5c65159SKalle Valo void *p_buf_addr_info, *p_last_buf_addr_info; 4640d5c65159SKalle Valo struct hal_rx_desc *rx_desc; 4641d5c65159SKalle Valo void *rx_msdu_link_desc; 4642d5c65159SKalle Valo dma_addr_t paddr; 4643d5c65159SKalle Valo u16 num_msdus = 0; 4644d5c65159SKalle Valo u32 rx_buf_size, rx_pkt_offset, sw_cookie; 4645d5c65159SKalle Valo u32 rx_bufs_used = 0, i = 0; 4646d5c65159SKalle Valo u32 msdu_ppdu_id = 0, msdu_cnt = 0; 4647d5c65159SKalle Valo u32 total_len = 0, frag_len = 0; 4648d5c65159SKalle Valo bool is_frag, is_first_msdu; 4649d5c65159SKalle Valo bool drop_mpdu = false; 4650d5c65159SKalle Valo struct ath11k_skb_rxcb *rxcb; 4651d5c65159SKalle Valo struct hal_reo_entrance_ring *ent_desc = 4652d5c65159SKalle Valo (struct hal_reo_entrance_ring *)ring_entry; 4653d5c65159SKalle Valo int buf_id; 4654701e48a4SCarl Huang u32 rx_link_buf_info[2]; 4655701e48a4SCarl Huang u8 rbm; 4656701e48a4SCarl Huang 4657701e48a4SCarl Huang if (!ar->ab->hw_params.rxdma1_enable) 4658701e48a4SCarl Huang rx_ring = &dp->rx_refill_buf_ring; 4659d5c65159SKalle Valo 4660d5c65159SKalle Valo ath11k_hal_rx_reo_ent_buf_paddr_get(ring_entry, &paddr, 4661701e48a4SCarl Huang &sw_cookie, 4662701e48a4SCarl Huang &p_last_buf_addr_info, &rbm, 4663d5c65159SKalle Valo &msdu_cnt); 4664d5c65159SKalle Valo 4665d5c65159SKalle Valo if (FIELD_GET(HAL_REO_ENTR_RING_INFO1_RXDMA_PUSH_REASON, 4666d5c65159SKalle Valo ent_desc->info1) == 4667d5c65159SKalle Valo HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED) { 4668d5c65159SKalle Valo u8 rxdma_err = 4669d5c65159SKalle Valo FIELD_GET(HAL_REO_ENTR_RING_INFO1_RXDMA_ERROR_CODE, 4670d5c65159SKalle Valo ent_desc->info1); 4671d5c65159SKalle Valo if (rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_FLUSH_REQUEST_ERR || 4672d5c65159SKalle Valo rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_MPDU_LEN_ERR || 4673d5c65159SKalle Valo rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_OVERFLOW_ERR) { 4674d5c65159SKalle Valo drop_mpdu = true; 4675d5c65159SKalle Valo pmon->rx_mon_stats.dest_mpdu_drop++; 4676d5c65159SKalle Valo } 4677d5c65159SKalle Valo } 4678d5c65159SKalle Valo 4679d5c65159SKalle Valo is_frag = false; 4680d5c65159SKalle Valo is_first_msdu = true; 4681d5c65159SKalle Valo 4682d5c65159SKalle Valo do { 4683d5c65159SKalle Valo if (pmon->mon_last_linkdesc_paddr == paddr) { 4684d5c65159SKalle Valo pmon->rx_mon_stats.dup_mon_linkdesc_cnt++; 4685d5c65159SKalle Valo return rx_bufs_used; 4686d5c65159SKalle Valo } 4687d5c65159SKalle Valo 4688701e48a4SCarl Huang if (ar->ab->hw_params.rxdma1_enable) 4689d5c65159SKalle Valo rx_msdu_link_desc = 4690d5c65159SKalle Valo (void *)pmon->link_desc_banks[sw_cookie].vaddr + 4691d5c65159SKalle Valo (paddr - pmon->link_desc_banks[sw_cookie].paddr); 4692701e48a4SCarl Huang else 4693701e48a4SCarl Huang rx_msdu_link_desc = 4694701e48a4SCarl Huang (void *)ar->ab->dp.link_desc_banks[sw_cookie].vaddr + 4695701e48a4SCarl Huang (paddr - ar->ab->dp.link_desc_banks[sw_cookie].paddr); 4696d5c65159SKalle Valo 4697d5c65159SKalle Valo ath11k_hal_rx_msdu_list_get(ar, rx_msdu_link_desc, &msdu_list, 4698d5c65159SKalle Valo &num_msdus); 4699d5c65159SKalle Valo 4700d5c65159SKalle Valo for (i = 0; i < num_msdus; i++) { 4701d5c65159SKalle Valo u32 l2_hdr_offset; 4702d5c65159SKalle Valo 4703d5c65159SKalle Valo if (pmon->mon_last_buf_cookie == msdu_list.sw_cookie[i]) { 4704d5c65159SKalle Valo ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 4705d5c65159SKalle Valo "i %d last_cookie %d is same\n", 4706d5c65159SKalle Valo i, pmon->mon_last_buf_cookie); 4707d5c65159SKalle Valo drop_mpdu = true; 4708d5c65159SKalle Valo pmon->rx_mon_stats.dup_mon_buf_cnt++; 4709d5c65159SKalle Valo continue; 4710d5c65159SKalle Valo } 4711d5c65159SKalle Valo buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, 4712d5c65159SKalle Valo msdu_list.sw_cookie[i]); 4713d5c65159SKalle Valo 4714d5c65159SKalle Valo spin_lock_bh(&rx_ring->idr_lock); 4715d5c65159SKalle Valo msdu = idr_find(&rx_ring->bufs_idr, buf_id); 4716d5c65159SKalle Valo spin_unlock_bh(&rx_ring->idr_lock); 4717d5c65159SKalle Valo if (!msdu) { 4718d5c65159SKalle Valo ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 4719d5c65159SKalle Valo "msdu_pop: invalid buf_id %d\n", buf_id); 4720d5c65159SKalle Valo break; 4721d5c65159SKalle Valo } 4722d5c65159SKalle Valo rxcb = ATH11K_SKB_RXCB(msdu); 4723d5c65159SKalle Valo if (!rxcb->unmapped) { 4724d5c65159SKalle Valo dma_unmap_single(ar->ab->dev, rxcb->paddr, 4725d5c65159SKalle Valo msdu->len + 4726d5c65159SKalle Valo skb_tailroom(msdu), 4727d5c65159SKalle Valo DMA_FROM_DEVICE); 4728d5c65159SKalle Valo rxcb->unmapped = 1; 4729d5c65159SKalle Valo } 4730d5c65159SKalle Valo if (drop_mpdu) { 4731d5c65159SKalle Valo ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 4732d5c65159SKalle Valo "i %d drop msdu %p *ppdu_id %x\n", 4733d5c65159SKalle Valo i, msdu, *ppdu_id); 4734d5c65159SKalle Valo dev_kfree_skb_any(msdu); 4735d5c65159SKalle Valo msdu = NULL; 4736d5c65159SKalle Valo goto next_msdu; 4737d5c65159SKalle Valo } 4738d5c65159SKalle Valo 4739d5c65159SKalle Valo rx_desc = (struct hal_rx_desc *)msdu->data; 4740d5c65159SKalle Valo 4741d5c65159SKalle Valo rx_pkt_offset = sizeof(struct hal_rx_desc); 4742e678fbd4SKarthikeyan Periyasamy l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, rx_desc); 4743d5c65159SKalle Valo 4744d5c65159SKalle Valo if (is_first_msdu) { 4745e678fbd4SKarthikeyan Periyasamy if (!ath11k_dp_rxdesc_mpdu_valid(ar->ab, rx_desc)) { 4746d5c65159SKalle Valo drop_mpdu = true; 4747d5c65159SKalle Valo dev_kfree_skb_any(msdu); 4748d5c65159SKalle Valo msdu = NULL; 4749d5c65159SKalle Valo pmon->mon_last_linkdesc_paddr = paddr; 4750d5c65159SKalle Valo goto next_msdu; 4751d5c65159SKalle Valo } 4752d5c65159SKalle Valo 4753d5c65159SKalle Valo msdu_ppdu_id = 4754e678fbd4SKarthikeyan Periyasamy ath11k_dp_rxdesc_get_ppduid(ar->ab, rx_desc); 4755d5c65159SKalle Valo 4756d5c65159SKalle Valo if (ath11k_dp_rx_mon_comp_ppduid(msdu_ppdu_id, 4757d5c65159SKalle Valo ppdu_id, 47585e02bc73SMiles Hu &rx_bufs_used)) { 47595e02bc73SMiles Hu if (rx_bufs_used) { 47605e02bc73SMiles Hu drop_mpdu = true; 47615e02bc73SMiles Hu dev_kfree_skb_any(msdu); 47625e02bc73SMiles Hu msdu = NULL; 47635e02bc73SMiles Hu goto next_msdu; 47645e02bc73SMiles Hu } 4765d5c65159SKalle Valo return rx_bufs_used; 47665e02bc73SMiles Hu } 4767d5c65159SKalle Valo pmon->mon_last_linkdesc_paddr = paddr; 4768d5c65159SKalle Valo is_first_msdu = false; 4769d5c65159SKalle Valo } 4770d5c65159SKalle Valo ath11k_dp_mon_get_buf_len(&msdu_list.msdu_info[i], 4771d5c65159SKalle Valo &is_frag, &total_len, 4772d5c65159SKalle Valo &frag_len, &msdu_cnt); 4773d5c65159SKalle Valo rx_buf_size = rx_pkt_offset + l2_hdr_offset + frag_len; 4774d5c65159SKalle Valo 4775d5c65159SKalle Valo ath11k_dp_pkt_set_pktlen(msdu, rx_buf_size); 4776d5c65159SKalle Valo 4777d5c65159SKalle Valo if (!(*head_msdu)) 4778d5c65159SKalle Valo *head_msdu = msdu; 4779d5c65159SKalle Valo else if (last) 4780d5c65159SKalle Valo last->next = msdu; 4781d5c65159SKalle Valo 4782d5c65159SKalle Valo last = msdu; 4783d5c65159SKalle Valo next_msdu: 4784d5c65159SKalle Valo pmon->mon_last_buf_cookie = msdu_list.sw_cookie[i]; 4785d5c65159SKalle Valo rx_bufs_used++; 4786d5c65159SKalle Valo spin_lock_bh(&rx_ring->idr_lock); 4787d5c65159SKalle Valo idr_remove(&rx_ring->bufs_idr, buf_id); 4788d5c65159SKalle Valo spin_unlock_bh(&rx_ring->idr_lock); 4789d5c65159SKalle Valo } 4790d5c65159SKalle Valo 4791701e48a4SCarl Huang ath11k_hal_rx_buf_addr_info_set(rx_link_buf_info, paddr, sw_cookie, rbm); 4792701e48a4SCarl Huang 4793d5c65159SKalle Valo ath11k_dp_rx_mon_next_link_desc_get(rx_msdu_link_desc, &paddr, 4794701e48a4SCarl Huang &sw_cookie, &rbm, 4795d5c65159SKalle Valo &p_buf_addr_info); 4796d5c65159SKalle Valo 4797701e48a4SCarl Huang if (ar->ab->hw_params.rxdma1_enable) { 4798d5c65159SKalle Valo if (ath11k_dp_rx_monitor_link_desc_return(ar, 4799d5c65159SKalle Valo p_last_buf_addr_info, 4800d5c65159SKalle Valo dp->mac_id)) 4801d5c65159SKalle Valo ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 4802d5c65159SKalle Valo "dp_rx_monitor_link_desc_return failed"); 4803701e48a4SCarl Huang } else { 4804701e48a4SCarl Huang ath11k_dp_rx_link_desc_return(ar->ab, rx_link_buf_info, 4805701e48a4SCarl Huang HAL_WBM_REL_BM_ACT_PUT_IN_IDLE); 4806701e48a4SCarl Huang } 4807d5c65159SKalle Valo 4808d5c65159SKalle Valo p_last_buf_addr_info = p_buf_addr_info; 4809d5c65159SKalle Valo 4810d5c65159SKalle Valo } while (paddr && msdu_cnt); 4811d5c65159SKalle Valo 4812d5c65159SKalle Valo if (last) 4813d5c65159SKalle Valo last->next = NULL; 4814d5c65159SKalle Valo 4815d5c65159SKalle Valo *tail_msdu = msdu; 4816d5c65159SKalle Valo 4817d5c65159SKalle Valo if (msdu_cnt == 0) 4818d5c65159SKalle Valo *npackets = 1; 4819d5c65159SKalle Valo 4820d5c65159SKalle Valo return rx_bufs_used; 4821d5c65159SKalle Valo } 4822d5c65159SKalle Valo 4823e678fbd4SKarthikeyan Periyasamy static void ath11k_dp_rx_msdus_set_payload(struct ath11k *ar, struct sk_buff *msdu) 4824d5c65159SKalle Valo { 4825d5c65159SKalle Valo u32 rx_pkt_offset, l2_hdr_offset; 4826d5c65159SKalle Valo 4827e678fbd4SKarthikeyan Periyasamy rx_pkt_offset = ar->ab->hw_params.hal_desc_sz; 4828e678fbd4SKarthikeyan Periyasamy l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, 4829e678fbd4SKarthikeyan Periyasamy (struct hal_rx_desc *)msdu->data); 4830d5c65159SKalle Valo skb_pull(msdu, rx_pkt_offset + l2_hdr_offset); 4831d5c65159SKalle Valo } 4832d5c65159SKalle Valo 4833d5c65159SKalle Valo static struct sk_buff * 4834d5c65159SKalle Valo ath11k_dp_rx_mon_merg_msdus(struct ath11k *ar, 4835d5c65159SKalle Valo u32 mac_id, struct sk_buff *head_msdu, 4836d5c65159SKalle Valo struct sk_buff *last_msdu, 483778726489SP Praneesh struct ieee80211_rx_status *rxs, bool *fcs_err) 4838d5c65159SKalle Valo { 4839e678fbd4SKarthikeyan Periyasamy struct ath11k_base *ab = ar->ab; 48407210b4b7STim Gardner struct sk_buff *msdu, *prev_buf; 4841d5c65159SKalle Valo struct hal_rx_desc *rx_desc; 4842d5c65159SKalle Valo char *hdr_desc; 4843e678fbd4SKarthikeyan Periyasamy u8 *dest, decap_format; 4844d5c65159SKalle Valo struct ieee80211_hdr_3addr *wh; 4845e678fbd4SKarthikeyan Periyasamy struct rx_attention *rx_attention; 484678726489SP Praneesh u32 err_bitmap; 4847d5c65159SKalle Valo 4848d5c65159SKalle Valo if (!head_msdu) 4849d5c65159SKalle Valo goto err_merge_fail; 4850d5c65159SKalle Valo 4851d5c65159SKalle Valo rx_desc = (struct hal_rx_desc *)head_msdu->data; 4852e678fbd4SKarthikeyan Periyasamy rx_attention = ath11k_dp_rx_get_attention(ab, rx_desc); 485378726489SP Praneesh err_bitmap = ath11k_dp_rx_h_attn_mpdu_err(rx_attention); 485478726489SP Praneesh 485578726489SP Praneesh if (err_bitmap & DP_RX_MPDU_ERR_FCS) 485678726489SP Praneesh *fcs_err = true; 4857d5c65159SKalle Valo 4858e678fbd4SKarthikeyan Periyasamy if (ath11k_dp_rxdesc_get_mpdulen_err(rx_attention)) 4859d5c65159SKalle Valo return NULL; 4860d5c65159SKalle Valo 4861e678fbd4SKarthikeyan Periyasamy decap_format = ath11k_dp_rx_h_msdu_start_decap_type(ab, rx_desc); 4862d5c65159SKalle Valo 4863d5c65159SKalle Valo ath11k_dp_rx_h_ppdu(ar, rx_desc, rxs); 4864d5c65159SKalle Valo 4865d5c65159SKalle Valo if (decap_format == DP_RX_DECAP_TYPE_RAW) { 4866e678fbd4SKarthikeyan Periyasamy ath11k_dp_rx_msdus_set_payload(ar, head_msdu); 4867d5c65159SKalle Valo 4868d5c65159SKalle Valo prev_buf = head_msdu; 4869d5c65159SKalle Valo msdu = head_msdu->next; 4870d5c65159SKalle Valo 4871d5c65159SKalle Valo while (msdu) { 4872e678fbd4SKarthikeyan Periyasamy ath11k_dp_rx_msdus_set_payload(ar, msdu); 4873d5c65159SKalle Valo 4874d5c65159SKalle Valo prev_buf = msdu; 4875d5c65159SKalle Valo msdu = msdu->next; 4876d5c65159SKalle Valo } 4877d5c65159SKalle Valo 4878d5c65159SKalle Valo prev_buf->next = NULL; 4879d5c65159SKalle Valo 4880d5c65159SKalle Valo skb_trim(prev_buf, prev_buf->len - HAL_RX_FCS_LEN); 4881d5c65159SKalle Valo } else if (decap_format == DP_RX_DECAP_TYPE_NATIVE_WIFI) { 4882d5c65159SKalle Valo u8 qos_pkt = 0; 4883d5c65159SKalle Valo 4884d5c65159SKalle Valo rx_desc = (struct hal_rx_desc *)head_msdu->data; 4885e678fbd4SKarthikeyan Periyasamy hdr_desc = ath11k_dp_rxdesc_get_80211hdr(ab, rx_desc); 4886d5c65159SKalle Valo 4887d5c65159SKalle Valo /* Base size */ 4888d5c65159SKalle Valo wh = (struct ieee80211_hdr_3addr *)hdr_desc; 4889d5c65159SKalle Valo 489001d2f285SPradeep Kumar Chitrapu if (ieee80211_is_data_qos(wh->frame_control)) 4891d5c65159SKalle Valo qos_pkt = 1; 489201d2f285SPradeep Kumar Chitrapu 4893d5c65159SKalle Valo msdu = head_msdu; 4894d5c65159SKalle Valo 4895d5c65159SKalle Valo while (msdu) { 489601d2f285SPradeep Kumar Chitrapu ath11k_dp_rx_msdus_set_payload(ar, msdu); 4897d5c65159SKalle Valo if (qos_pkt) { 4898d5c65159SKalle Valo dest = skb_push(msdu, sizeof(__le16)); 4899d5c65159SKalle Valo if (!dest) 4900d5c65159SKalle Valo goto err_merge_fail; 490101d2f285SPradeep Kumar Chitrapu memcpy(dest, hdr_desc, sizeof(struct ieee80211_qos_hdr)); 4902d5c65159SKalle Valo } 4903d5c65159SKalle Valo prev_buf = msdu; 4904d5c65159SKalle Valo msdu = msdu->next; 4905d5c65159SKalle Valo } 4906d5c65159SKalle Valo dest = skb_put(prev_buf, HAL_RX_FCS_LEN); 4907d5c65159SKalle Valo if (!dest) 4908d5c65159SKalle Valo goto err_merge_fail; 4909d5c65159SKalle Valo 4910e678fbd4SKarthikeyan Periyasamy ath11k_dbg(ab, ATH11K_DBG_DATA, 4911cf036c41SKalle Valo "mpdu_buf %p mpdu_buf->len %u", 4912d5c65159SKalle Valo prev_buf, prev_buf->len); 4913d5c65159SKalle Valo } else { 4914e678fbd4SKarthikeyan Periyasamy ath11k_dbg(ab, ATH11K_DBG_DATA, 4915d5c65159SKalle Valo "decap format %d is not supported!\n", 4916d5c65159SKalle Valo decap_format); 4917d5c65159SKalle Valo goto err_merge_fail; 4918d5c65159SKalle Valo } 4919d5c65159SKalle Valo 4920d5c65159SKalle Valo return head_msdu; 4921d5c65159SKalle Valo 4922d5c65159SKalle Valo err_merge_fail: 4923d5c65159SKalle Valo return NULL; 4924d5c65159SKalle Valo } 4925d5c65159SKalle Valo 492601d2f285SPradeep Kumar Chitrapu static void 492701d2f285SPradeep Kumar Chitrapu ath11k_dp_rx_update_radiotap_he(struct hal_rx_mon_ppdu_info *rx_status, 492801d2f285SPradeep Kumar Chitrapu u8 *rtap_buf) 492901d2f285SPradeep Kumar Chitrapu { 493001d2f285SPradeep Kumar Chitrapu u32 rtap_len = 0; 493101d2f285SPradeep Kumar Chitrapu 493201d2f285SPradeep Kumar Chitrapu put_unaligned_le16(rx_status->he_data1, &rtap_buf[rtap_len]); 493301d2f285SPradeep Kumar Chitrapu rtap_len += 2; 493401d2f285SPradeep Kumar Chitrapu 493501d2f285SPradeep Kumar Chitrapu put_unaligned_le16(rx_status->he_data2, &rtap_buf[rtap_len]); 493601d2f285SPradeep Kumar Chitrapu rtap_len += 2; 493701d2f285SPradeep Kumar Chitrapu 493801d2f285SPradeep Kumar Chitrapu put_unaligned_le16(rx_status->he_data3, &rtap_buf[rtap_len]); 493901d2f285SPradeep Kumar Chitrapu rtap_len += 2; 494001d2f285SPradeep Kumar Chitrapu 494101d2f285SPradeep Kumar Chitrapu put_unaligned_le16(rx_status->he_data4, &rtap_buf[rtap_len]); 494201d2f285SPradeep Kumar Chitrapu rtap_len += 2; 494301d2f285SPradeep Kumar Chitrapu 494401d2f285SPradeep Kumar Chitrapu put_unaligned_le16(rx_status->he_data5, &rtap_buf[rtap_len]); 494501d2f285SPradeep Kumar Chitrapu rtap_len += 2; 494601d2f285SPradeep Kumar Chitrapu 494701d2f285SPradeep Kumar Chitrapu put_unaligned_le16(rx_status->he_data6, &rtap_buf[rtap_len]); 494801d2f285SPradeep Kumar Chitrapu } 494901d2f285SPradeep Kumar Chitrapu 495001d2f285SPradeep Kumar Chitrapu static void 495101d2f285SPradeep Kumar Chitrapu ath11k_dp_rx_update_radiotap_he_mu(struct hal_rx_mon_ppdu_info *rx_status, 495201d2f285SPradeep Kumar Chitrapu u8 *rtap_buf) 495301d2f285SPradeep Kumar Chitrapu { 495401d2f285SPradeep Kumar Chitrapu u32 rtap_len = 0; 495501d2f285SPradeep Kumar Chitrapu 495601d2f285SPradeep Kumar Chitrapu put_unaligned_le16(rx_status->he_flags1, &rtap_buf[rtap_len]); 495701d2f285SPradeep Kumar Chitrapu rtap_len += 2; 495801d2f285SPradeep Kumar Chitrapu 495901d2f285SPradeep Kumar Chitrapu put_unaligned_le16(rx_status->he_flags2, &rtap_buf[rtap_len]); 496001d2f285SPradeep Kumar Chitrapu rtap_len += 2; 496101d2f285SPradeep Kumar Chitrapu 496201d2f285SPradeep Kumar Chitrapu rtap_buf[rtap_len] = rx_status->he_RU[0]; 496301d2f285SPradeep Kumar Chitrapu rtap_len += 1; 496401d2f285SPradeep Kumar Chitrapu 496501d2f285SPradeep Kumar Chitrapu rtap_buf[rtap_len] = rx_status->he_RU[1]; 496601d2f285SPradeep Kumar Chitrapu rtap_len += 1; 496701d2f285SPradeep Kumar Chitrapu 496801d2f285SPradeep Kumar Chitrapu rtap_buf[rtap_len] = rx_status->he_RU[2]; 496901d2f285SPradeep Kumar Chitrapu rtap_len += 1; 497001d2f285SPradeep Kumar Chitrapu 497101d2f285SPradeep Kumar Chitrapu rtap_buf[rtap_len] = rx_status->he_RU[3]; 497201d2f285SPradeep Kumar Chitrapu } 497301d2f285SPradeep Kumar Chitrapu 4974ab0a9ef6SPradeep Kumar Chitrapu static void ath11k_update_radiotap(struct ath11k *ar, 4975ab0a9ef6SPradeep Kumar Chitrapu struct hal_rx_mon_ppdu_info *ppduinfo, 497601d2f285SPradeep Kumar Chitrapu struct sk_buff *mon_skb, 497701d2f285SPradeep Kumar Chitrapu struct ieee80211_rx_status *rxs) 497801d2f285SPradeep Kumar Chitrapu { 4979ab0a9ef6SPradeep Kumar Chitrapu struct ieee80211_supported_band *sband; 498001d2f285SPradeep Kumar Chitrapu u8 *ptr = NULL; 498101d2f285SPradeep Kumar Chitrapu 4982ab0a9ef6SPradeep Kumar Chitrapu rxs->flag |= RX_FLAG_MACTIME_START; 4983ab0a9ef6SPradeep Kumar Chitrapu rxs->signal = ppduinfo->rssi_comb + ATH11K_DEFAULT_NOISE_FLOOR; 4984ab0a9ef6SPradeep Kumar Chitrapu 4985ab0a9ef6SPradeep Kumar Chitrapu if (ppduinfo->nss) 4986ab0a9ef6SPradeep Kumar Chitrapu rxs->nss = ppduinfo->nss; 4987ab0a9ef6SPradeep Kumar Chitrapu 498801d2f285SPradeep Kumar Chitrapu if (ppduinfo->he_mu_flags) { 498901d2f285SPradeep Kumar Chitrapu rxs->flag |= RX_FLAG_RADIOTAP_HE_MU; 499001d2f285SPradeep Kumar Chitrapu rxs->encoding = RX_ENC_HE; 499101d2f285SPradeep Kumar Chitrapu ptr = skb_push(mon_skb, sizeof(struct ieee80211_radiotap_he_mu)); 499201d2f285SPradeep Kumar Chitrapu ath11k_dp_rx_update_radiotap_he_mu(ppduinfo, ptr); 4993ab0a9ef6SPradeep Kumar Chitrapu } else if (ppduinfo->he_flags) { 499401d2f285SPradeep Kumar Chitrapu rxs->flag |= RX_FLAG_RADIOTAP_HE; 499501d2f285SPradeep Kumar Chitrapu rxs->encoding = RX_ENC_HE; 499601d2f285SPradeep Kumar Chitrapu ptr = skb_push(mon_skb, sizeof(struct ieee80211_radiotap_he)); 499701d2f285SPradeep Kumar Chitrapu ath11k_dp_rx_update_radiotap_he(ppduinfo, ptr); 4998ab0a9ef6SPradeep Kumar Chitrapu rxs->rate_idx = ppduinfo->rate; 4999ab0a9ef6SPradeep Kumar Chitrapu } else if (ppduinfo->vht_flags) { 5000ab0a9ef6SPradeep Kumar Chitrapu rxs->encoding = RX_ENC_VHT; 5001ab0a9ef6SPradeep Kumar Chitrapu rxs->rate_idx = ppduinfo->rate; 5002ab0a9ef6SPradeep Kumar Chitrapu } else if (ppduinfo->ht_flags) { 5003ab0a9ef6SPradeep Kumar Chitrapu rxs->encoding = RX_ENC_HT; 5004ab0a9ef6SPradeep Kumar Chitrapu rxs->rate_idx = ppduinfo->rate; 5005ab0a9ef6SPradeep Kumar Chitrapu } else { 5006ab0a9ef6SPradeep Kumar Chitrapu rxs->encoding = RX_ENC_LEGACY; 5007ab0a9ef6SPradeep Kumar Chitrapu sband = &ar->mac.sbands[rxs->band]; 5008ab0a9ef6SPradeep Kumar Chitrapu rxs->rate_idx = ath11k_mac_hw_rate_to_idx(sband, ppduinfo->rate, 5009ab0a9ef6SPradeep Kumar Chitrapu ppduinfo->cck_flag); 501001d2f285SPradeep Kumar Chitrapu } 501101d2f285SPradeep Kumar Chitrapu 501201d2f285SPradeep Kumar Chitrapu rxs->mactime = ppduinfo->tsft; 501301d2f285SPradeep Kumar Chitrapu } 501401d2f285SPradeep Kumar Chitrapu 5015d5c65159SKalle Valo static int ath11k_dp_rx_mon_deliver(struct ath11k *ar, u32 mac_id, 5016d5c65159SKalle Valo struct sk_buff *head_msdu, 501701d2f285SPradeep Kumar Chitrapu struct hal_rx_mon_ppdu_info *ppduinfo, 5018d5c65159SKalle Valo struct sk_buff *tail_msdu, 5019d5c65159SKalle Valo struct napi_struct *napi) 5020d5c65159SKalle Valo { 5021d5c65159SKalle Valo struct ath11k_pdev_dp *dp = &ar->dp; 5022d5c65159SKalle Valo struct sk_buff *mon_skb, *skb_next, *header; 50232167fa60SSriram R struct ieee80211_rx_status *rxs = &dp->rx_status; 502478726489SP Praneesh bool fcs_err = false; 5025d5c65159SKalle Valo 5026d5c65159SKalle Valo mon_skb = ath11k_dp_rx_mon_merg_msdus(ar, mac_id, head_msdu, 502778726489SP Praneesh tail_msdu, rxs, &fcs_err); 5028d5c65159SKalle Valo 5029d5c65159SKalle Valo if (!mon_skb) 5030d5c65159SKalle Valo goto mon_deliver_fail; 5031d5c65159SKalle Valo 5032d5c65159SKalle Valo header = mon_skb; 5033d5c65159SKalle Valo 5034d5c65159SKalle Valo rxs->flag = 0; 503578726489SP Praneesh 503678726489SP Praneesh if (fcs_err) 503778726489SP Praneesh rxs->flag = RX_FLAG_FAILED_FCS_CRC; 503878726489SP Praneesh 5039d5c65159SKalle Valo do { 5040d5c65159SKalle Valo skb_next = mon_skb->next; 5041d5c65159SKalle Valo if (!skb_next) 5042d5c65159SKalle Valo rxs->flag &= ~RX_FLAG_AMSDU_MORE; 5043d5c65159SKalle Valo else 5044d5c65159SKalle Valo rxs->flag |= RX_FLAG_AMSDU_MORE; 5045d5c65159SKalle Valo 5046d5c65159SKalle Valo if (mon_skb == header) { 5047d5c65159SKalle Valo header = NULL; 5048d5c65159SKalle Valo rxs->flag &= ~RX_FLAG_ALLOW_SAME_PN; 5049d5c65159SKalle Valo } else { 5050d5c65159SKalle Valo rxs->flag |= RX_FLAG_ALLOW_SAME_PN; 5051d5c65159SKalle Valo } 5052950b43f8SNagarajan Maran rxs->flag |= RX_FLAG_ONLY_MONITOR; 5053ab0a9ef6SPradeep Kumar Chitrapu ath11k_update_radiotap(ar, ppduinfo, mon_skb, rxs); 5054d5c65159SKalle Valo 50552167fa60SSriram R ath11k_dp_rx_deliver_msdu(ar, napi, mon_skb, rxs); 5056d5c65159SKalle Valo mon_skb = skb_next; 50575e02bc73SMiles Hu } while (mon_skb); 5058d5c65159SKalle Valo rxs->flag = 0; 5059d5c65159SKalle Valo 5060d5c65159SKalle Valo return 0; 5061d5c65159SKalle Valo 5062d5c65159SKalle Valo mon_deliver_fail: 5063d5c65159SKalle Valo mon_skb = head_msdu; 5064d5c65159SKalle Valo while (mon_skb) { 5065d5c65159SKalle Valo skb_next = mon_skb->next; 5066d5c65159SKalle Valo dev_kfree_skb_any(mon_skb); 5067d5c65159SKalle Valo mon_skb = skb_next; 5068d5c65159SKalle Valo } 5069d5c65159SKalle Valo return -EINVAL; 5070d5c65159SKalle Valo } 5071d5c65159SKalle Valo 50721e15aacdSKarthikeyan Kathirvel /* The destination ring processing is stuck if the destination is not 50731e15aacdSKarthikeyan Kathirvel * moving while status ring moves 16 PPDU. The destination ring processing 50741e15aacdSKarthikeyan Kathirvel * skips this destination ring PPDU as a workaround. 50751e15aacdSKarthikeyan Kathirvel */ 50761e15aacdSKarthikeyan Kathirvel #define MON_DEST_RING_STUCK_MAX_CNT 16 50771e15aacdSKarthikeyan Kathirvel 5078701e48a4SCarl Huang static void ath11k_dp_rx_mon_dest_process(struct ath11k *ar, int mac_id, 5079701e48a4SCarl Huang u32 quota, struct napi_struct *napi) 5080d5c65159SKalle Valo { 5081d5c65159SKalle Valo struct ath11k_pdev_dp *dp = &ar->dp; 5082d5c65159SKalle Valo struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data; 5083734223d7SBaochen Qiang const struct ath11k_hw_hal_params *hal_params; 5084d5c65159SKalle Valo void *ring_entry; 5085d5c65159SKalle Valo void *mon_dst_srng; 5086d5c65159SKalle Valo u32 ppdu_id; 5087d5c65159SKalle Valo u32 rx_bufs_used; 5088701e48a4SCarl Huang u32 ring_id; 5089d5c65159SKalle Valo struct ath11k_pdev_mon_stats *rx_mon_stats; 5090d5c65159SKalle Valo u32 npackets = 0; 50911e15aacdSKarthikeyan Kathirvel u32 mpdu_rx_bufs_used; 5092d5c65159SKalle Valo 5093701e48a4SCarl Huang if (ar->ab->hw_params.rxdma1_enable) 5094701e48a4SCarl Huang ring_id = dp->rxdma_mon_dst_ring.ring_id; 5095701e48a4SCarl Huang else 5096701e48a4SCarl Huang ring_id = dp->rxdma_err_dst_ring[mac_id].ring_id; 5097701e48a4SCarl Huang 5098701e48a4SCarl Huang mon_dst_srng = &ar->ab->hal.srng_list[ring_id]; 5099d5c65159SKalle Valo 5100d5c65159SKalle Valo if (!mon_dst_srng) { 5101d5c65159SKalle Valo ath11k_warn(ar->ab, 5102cf036c41SKalle Valo "HAL Monitor Destination Ring Init Failed -- %p", 5103d5c65159SKalle Valo mon_dst_srng); 5104d5c65159SKalle Valo return; 5105d5c65159SKalle Valo } 5106d5c65159SKalle Valo 5107d5c65159SKalle Valo spin_lock_bh(&pmon->mon_lock); 5108d5c65159SKalle Valo 5109d5c65159SKalle Valo ath11k_hal_srng_access_begin(ar->ab, mon_dst_srng); 5110d5c65159SKalle Valo 5111d5c65159SKalle Valo ppdu_id = pmon->mon_ppdu_info.ppdu_id; 5112d5c65159SKalle Valo rx_bufs_used = 0; 5113d5c65159SKalle Valo rx_mon_stats = &pmon->rx_mon_stats; 5114d5c65159SKalle Valo 5115d5c65159SKalle Valo while ((ring_entry = ath11k_hal_srng_dst_peek(ar->ab, mon_dst_srng))) { 5116d5c65159SKalle Valo struct sk_buff *head_msdu, *tail_msdu; 5117d5c65159SKalle Valo 5118d5c65159SKalle Valo head_msdu = NULL; 5119d5c65159SKalle Valo tail_msdu = NULL; 5120d5c65159SKalle Valo 51211e15aacdSKarthikeyan Kathirvel mpdu_rx_bufs_used = ath11k_dp_rx_mon_mpdu_pop(ar, mac_id, ring_entry, 5122d5c65159SKalle Valo &head_msdu, 5123d5c65159SKalle Valo &tail_msdu, 5124d5c65159SKalle Valo &npackets, &ppdu_id); 5125d5c65159SKalle Valo 51261e15aacdSKarthikeyan Kathirvel rx_bufs_used += mpdu_rx_bufs_used; 51271e15aacdSKarthikeyan Kathirvel 51281e15aacdSKarthikeyan Kathirvel if (mpdu_rx_bufs_used) { 51291e15aacdSKarthikeyan Kathirvel dp->mon_dest_ring_stuck_cnt = 0; 51301e15aacdSKarthikeyan Kathirvel } else { 51311e15aacdSKarthikeyan Kathirvel dp->mon_dest_ring_stuck_cnt++; 51321e15aacdSKarthikeyan Kathirvel rx_mon_stats->dest_mon_not_reaped++; 51331e15aacdSKarthikeyan Kathirvel } 51341e15aacdSKarthikeyan Kathirvel 51351e15aacdSKarthikeyan Kathirvel if (dp->mon_dest_ring_stuck_cnt > MON_DEST_RING_STUCK_MAX_CNT) { 51361e15aacdSKarthikeyan Kathirvel rx_mon_stats->dest_mon_stuck++; 51371e15aacdSKarthikeyan Kathirvel ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 51381e15aacdSKarthikeyan Kathirvel "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", 51391e15aacdSKarthikeyan Kathirvel pmon->mon_ppdu_info.ppdu_id, ppdu_id, 51401e15aacdSKarthikeyan Kathirvel dp->mon_dest_ring_stuck_cnt, 51411e15aacdSKarthikeyan Kathirvel rx_mon_stats->dest_mon_not_reaped, 51421e15aacdSKarthikeyan Kathirvel rx_mon_stats->dest_mon_stuck); 51431e15aacdSKarthikeyan Kathirvel pmon->mon_ppdu_info.ppdu_id = ppdu_id; 51441e15aacdSKarthikeyan Kathirvel continue; 51451e15aacdSKarthikeyan Kathirvel } 51461e15aacdSKarthikeyan Kathirvel 5147d5c65159SKalle Valo if (ppdu_id != pmon->mon_ppdu_info.ppdu_id) { 5148d5c65159SKalle Valo pmon->mon_ppdu_status = DP_PPDU_STATUS_START; 5149d5c65159SKalle Valo ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 51501e15aacdSKarthikeyan Kathirvel "dest_rx: new ppdu_id %x != status ppdu_id %x dest_mon_not_reaped = %u dest_mon_stuck = %u\n", 51511e15aacdSKarthikeyan Kathirvel ppdu_id, pmon->mon_ppdu_info.ppdu_id, 51521e15aacdSKarthikeyan Kathirvel rx_mon_stats->dest_mon_not_reaped, 51531e15aacdSKarthikeyan Kathirvel rx_mon_stats->dest_mon_stuck); 5154d5c65159SKalle Valo break; 5155d5c65159SKalle Valo } 5156d5c65159SKalle Valo if (head_msdu && tail_msdu) { 5157d5c65159SKalle Valo ath11k_dp_rx_mon_deliver(ar, dp->mac_id, head_msdu, 515801d2f285SPradeep Kumar Chitrapu &pmon->mon_ppdu_info, 5159d5c65159SKalle Valo tail_msdu, napi); 5160d5c65159SKalle Valo rx_mon_stats->dest_mpdu_done++; 5161d5c65159SKalle Valo } 5162d5c65159SKalle Valo 5163d5c65159SKalle Valo ring_entry = ath11k_hal_srng_dst_get_next_entry(ar->ab, 5164d5c65159SKalle Valo mon_dst_srng); 5165d5c65159SKalle Valo } 5166d5c65159SKalle Valo ath11k_hal_srng_access_end(ar->ab, mon_dst_srng); 5167d5c65159SKalle Valo 5168d5c65159SKalle Valo spin_unlock_bh(&pmon->mon_lock); 5169d5c65159SKalle Valo 5170d5c65159SKalle Valo if (rx_bufs_used) { 5171d5c65159SKalle Valo rx_mon_stats->dest_ppdu_done++; 5172734223d7SBaochen Qiang hal_params = ar->ab->hw_params.hal_params; 5173734223d7SBaochen Qiang 5174701e48a4SCarl Huang if (ar->ab->hw_params.rxdma1_enable) 5175d5c65159SKalle Valo ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, 5176d5c65159SKalle Valo &dp->rxdma_mon_buf_ring, 5177d5c65159SKalle Valo rx_bufs_used, 5178734223d7SBaochen Qiang hal_params->rx_buf_rbm); 5179701e48a4SCarl Huang else 5180701e48a4SCarl Huang ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, 5181701e48a4SCarl Huang &dp->rx_refill_buf_ring, 5182701e48a4SCarl Huang rx_bufs_used, 5183734223d7SBaochen Qiang hal_params->rx_buf_rbm); 5184d5c65159SKalle Valo } 5185d5c65159SKalle Valo } 5186d5c65159SKalle Valo 51873cd04a43SAloka Dixit int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id, 51883cd04a43SAloka Dixit struct napi_struct *napi, int budget) 51893cd04a43SAloka Dixit { 51903cd04a43SAloka Dixit struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); 51913cd04a43SAloka Dixit enum hal_rx_mon_status hal_status; 51923cd04a43SAloka Dixit struct sk_buff *skb; 51933cd04a43SAloka Dixit struct sk_buff_head skb_list; 51943cd04a43SAloka Dixit struct ath11k_peer *peer; 51953cd04a43SAloka Dixit struct ath11k_sta *arsta; 51963cd04a43SAloka Dixit int num_buffs_reaped = 0; 51973cd04a43SAloka Dixit u32 rx_buf_sz; 5198dca857f0SAnilkumar Kolli u16 log_type; 51993cd04a43SAloka Dixit struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&ar->dp.mon_data; 52003cd04a43SAloka Dixit struct ath11k_pdev_mon_stats *rx_mon_stats = &pmon->rx_mon_stats; 52013cd04a43SAloka Dixit struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info; 52023cd04a43SAloka Dixit 52033cd04a43SAloka Dixit __skb_queue_head_init(&skb_list); 52043cd04a43SAloka Dixit 52053cd04a43SAloka Dixit num_buffs_reaped = ath11k_dp_rx_reap_mon_status_ring(ab, mac_id, &budget, 52063cd04a43SAloka Dixit &skb_list); 52073cd04a43SAloka Dixit if (!num_buffs_reaped) 52083cd04a43SAloka Dixit goto exit; 52093cd04a43SAloka Dixit 52103cd04a43SAloka Dixit memset(ppdu_info, 0, sizeof(*ppdu_info)); 52113cd04a43SAloka Dixit ppdu_info->peer_id = HAL_INVALID_PEERID; 52123cd04a43SAloka Dixit 52133cd04a43SAloka Dixit while ((skb = __skb_dequeue(&skb_list))) { 52143cd04a43SAloka Dixit if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar)) { 52153cd04a43SAloka Dixit log_type = ATH11K_PKTLOG_TYPE_LITE_RX; 52163cd04a43SAloka Dixit rx_buf_sz = DP_RX_BUFFER_SIZE_LITE; 52173cd04a43SAloka Dixit } else if (ath11k_debugfs_is_pktlog_rx_stats_enabled(ar)) { 52183cd04a43SAloka Dixit log_type = ATH11K_PKTLOG_TYPE_RX_STATBUF; 52193cd04a43SAloka Dixit rx_buf_sz = DP_RX_BUFFER_SIZE; 5220dca857f0SAnilkumar Kolli } else { 5221dca857f0SAnilkumar Kolli log_type = ATH11K_PKTLOG_TYPE_INVALID; 5222dca857f0SAnilkumar Kolli rx_buf_sz = 0; 52233cd04a43SAloka Dixit } 52243cd04a43SAloka Dixit 5225dca857f0SAnilkumar Kolli if (log_type != ATH11K_PKTLOG_TYPE_INVALID) 52263cd04a43SAloka Dixit trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); 52273cd04a43SAloka Dixit 5228a20ed60bSWen Gong memset(ppdu_info, 0, sizeof(*ppdu_info)); 5229a20ed60bSWen Gong ppdu_info->peer_id = HAL_INVALID_PEERID; 52303cd04a43SAloka Dixit hal_status = ath11k_hal_rx_parse_mon_status(ab, ppdu_info, skb); 52313cd04a43SAloka Dixit 52323cd04a43SAloka Dixit if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags) && 52333cd04a43SAloka Dixit pmon->mon_ppdu_status == DP_PPDU_STATUS_START && 52343cd04a43SAloka Dixit hal_status == HAL_TLV_STATUS_PPDU_DONE) { 52353cd04a43SAloka Dixit rx_mon_stats->status_ppdu_done++; 52363cd04a43SAloka Dixit pmon->mon_ppdu_status = DP_PPDU_STATUS_DONE; 52373cd04a43SAloka Dixit ath11k_dp_rx_mon_dest_process(ar, mac_id, budget, napi); 52383cd04a43SAloka Dixit pmon->mon_ppdu_status = DP_PPDU_STATUS_START; 52393cd04a43SAloka Dixit } 52403cd04a43SAloka Dixit 52413cd04a43SAloka Dixit if (ppdu_info->peer_id == HAL_INVALID_PEERID || 52423cd04a43SAloka Dixit hal_status != HAL_RX_MON_STATUS_PPDU_DONE) { 52433cd04a43SAloka Dixit dev_kfree_skb_any(skb); 52443cd04a43SAloka Dixit continue; 52453cd04a43SAloka Dixit } 52463cd04a43SAloka Dixit 52473cd04a43SAloka Dixit rcu_read_lock(); 52483cd04a43SAloka Dixit spin_lock_bh(&ab->base_lock); 52493cd04a43SAloka Dixit peer = ath11k_peer_find_by_id(ab, ppdu_info->peer_id); 52503cd04a43SAloka Dixit 52513cd04a43SAloka Dixit if (!peer || !peer->sta) { 52523cd04a43SAloka Dixit ath11k_dbg(ab, ATH11K_DBG_DATA, 52533cd04a43SAloka Dixit "failed to find the peer with peer_id %d\n", 52543cd04a43SAloka Dixit ppdu_info->peer_id); 52553cd04a43SAloka Dixit goto next_skb; 52563cd04a43SAloka Dixit } 52573cd04a43SAloka Dixit 52583cd04a43SAloka Dixit arsta = (struct ath11k_sta *)peer->sta->drv_priv; 52593cd04a43SAloka Dixit ath11k_dp_rx_update_peer_stats(arsta, ppdu_info); 52603cd04a43SAloka Dixit 52613cd04a43SAloka Dixit if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr)) 52623cd04a43SAloka Dixit trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); 52633cd04a43SAloka Dixit 52643cd04a43SAloka Dixit next_skb: 52653cd04a43SAloka Dixit spin_unlock_bh(&ab->base_lock); 52663cd04a43SAloka Dixit rcu_read_unlock(); 52673cd04a43SAloka Dixit 52683cd04a43SAloka Dixit dev_kfree_skb_any(skb); 52693cd04a43SAloka Dixit memset(ppdu_info, 0, sizeof(*ppdu_info)); 52703cd04a43SAloka Dixit ppdu_info->peer_id = HAL_INVALID_PEERID; 52713cd04a43SAloka Dixit } 52723cd04a43SAloka Dixit exit: 52733cd04a43SAloka Dixit return num_buffs_reaped; 52743cd04a43SAloka Dixit } 52753cd04a43SAloka Dixit 52767e2ea2e9SAnilkumar Kolli static u32 52777e2ea2e9SAnilkumar Kolli ath11k_dp_rx_full_mon_mpdu_pop(struct ath11k *ar, 52787e2ea2e9SAnilkumar Kolli void *ring_entry, struct sk_buff **head_msdu, 52797e2ea2e9SAnilkumar Kolli struct sk_buff **tail_msdu, 52807e2ea2e9SAnilkumar Kolli struct hal_sw_mon_ring_entries *sw_mon_entries) 52817e2ea2e9SAnilkumar Kolli { 52827e2ea2e9SAnilkumar Kolli struct ath11k_pdev_dp *dp = &ar->dp; 52837e2ea2e9SAnilkumar Kolli struct ath11k_mon_data *pmon = &dp->mon_data; 52847e2ea2e9SAnilkumar Kolli struct dp_rxdma_ring *rx_ring = &dp->rxdma_mon_buf_ring; 52857e2ea2e9SAnilkumar Kolli struct sk_buff *msdu = NULL, *last = NULL; 52867e2ea2e9SAnilkumar Kolli struct hal_sw_monitor_ring *sw_desc = ring_entry; 52877e2ea2e9SAnilkumar Kolli struct hal_rx_msdu_list msdu_list; 52887e2ea2e9SAnilkumar Kolli struct hal_rx_desc *rx_desc; 52897e2ea2e9SAnilkumar Kolli struct ath11k_skb_rxcb *rxcb; 52907e2ea2e9SAnilkumar Kolli void *rx_msdu_link_desc; 52917e2ea2e9SAnilkumar Kolli void *p_buf_addr_info, *p_last_buf_addr_info; 52927e2ea2e9SAnilkumar Kolli int buf_id, i = 0; 52937e2ea2e9SAnilkumar Kolli u32 rx_buf_size, rx_pkt_offset, l2_hdr_offset; 52947e2ea2e9SAnilkumar Kolli u32 rx_bufs_used = 0, msdu_cnt = 0; 52957e2ea2e9SAnilkumar Kolli u32 total_len = 0, frag_len = 0, sw_cookie; 52967e2ea2e9SAnilkumar Kolli u16 num_msdus = 0; 52977e2ea2e9SAnilkumar Kolli u8 rxdma_err, rbm; 52987e2ea2e9SAnilkumar Kolli bool is_frag, is_first_msdu; 52997e2ea2e9SAnilkumar Kolli bool drop_mpdu = false; 53007e2ea2e9SAnilkumar Kolli 53017e2ea2e9SAnilkumar Kolli ath11k_hal_rx_sw_mon_ring_buf_paddr_get(ring_entry, sw_mon_entries); 53027e2ea2e9SAnilkumar Kolli 53037e2ea2e9SAnilkumar Kolli sw_cookie = sw_mon_entries->mon_dst_sw_cookie; 53047e2ea2e9SAnilkumar Kolli sw_mon_entries->end_of_ppdu = false; 53057e2ea2e9SAnilkumar Kolli sw_mon_entries->drop_ppdu = false; 53067e2ea2e9SAnilkumar Kolli p_last_buf_addr_info = sw_mon_entries->dst_buf_addr_info; 53077e2ea2e9SAnilkumar Kolli msdu_cnt = sw_mon_entries->msdu_cnt; 53087e2ea2e9SAnilkumar Kolli 53097e2ea2e9SAnilkumar Kolli sw_mon_entries->end_of_ppdu = 53107e2ea2e9SAnilkumar Kolli FIELD_GET(HAL_SW_MON_RING_INFO0_END_OF_PPDU, sw_desc->info0); 53117e2ea2e9SAnilkumar Kolli if (sw_mon_entries->end_of_ppdu) 53127e2ea2e9SAnilkumar Kolli return rx_bufs_used; 53137e2ea2e9SAnilkumar Kolli 53147e2ea2e9SAnilkumar Kolli if (FIELD_GET(HAL_SW_MON_RING_INFO0_RXDMA_PUSH_REASON, 53157e2ea2e9SAnilkumar Kolli sw_desc->info0) == 53167e2ea2e9SAnilkumar Kolli HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED) { 53177e2ea2e9SAnilkumar Kolli rxdma_err = 53187e2ea2e9SAnilkumar Kolli FIELD_GET(HAL_SW_MON_RING_INFO0_RXDMA_ERROR_CODE, 53197e2ea2e9SAnilkumar Kolli sw_desc->info0); 53207e2ea2e9SAnilkumar Kolli if (rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_FLUSH_REQUEST_ERR || 53217e2ea2e9SAnilkumar Kolli rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_MPDU_LEN_ERR || 53227e2ea2e9SAnilkumar Kolli rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_OVERFLOW_ERR) { 53237e2ea2e9SAnilkumar Kolli pmon->rx_mon_stats.dest_mpdu_drop++; 53247e2ea2e9SAnilkumar Kolli drop_mpdu = true; 53257e2ea2e9SAnilkumar Kolli } 53267e2ea2e9SAnilkumar Kolli } 53277e2ea2e9SAnilkumar Kolli 53287e2ea2e9SAnilkumar Kolli is_frag = false; 53297e2ea2e9SAnilkumar Kolli is_first_msdu = true; 53307e2ea2e9SAnilkumar Kolli 53317e2ea2e9SAnilkumar Kolli do { 53327e2ea2e9SAnilkumar Kolli rx_msdu_link_desc = 53337e2ea2e9SAnilkumar Kolli (u8 *)pmon->link_desc_banks[sw_cookie].vaddr + 53347e2ea2e9SAnilkumar Kolli (sw_mon_entries->mon_dst_paddr - 53357e2ea2e9SAnilkumar Kolli pmon->link_desc_banks[sw_cookie].paddr); 53367e2ea2e9SAnilkumar Kolli 53377e2ea2e9SAnilkumar Kolli ath11k_hal_rx_msdu_list_get(ar, rx_msdu_link_desc, &msdu_list, 53387e2ea2e9SAnilkumar Kolli &num_msdus); 53397e2ea2e9SAnilkumar Kolli 53407e2ea2e9SAnilkumar Kolli for (i = 0; i < num_msdus; i++) { 53417e2ea2e9SAnilkumar Kolli buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, 53427e2ea2e9SAnilkumar Kolli msdu_list.sw_cookie[i]); 53437e2ea2e9SAnilkumar Kolli 53447e2ea2e9SAnilkumar Kolli spin_lock_bh(&rx_ring->idr_lock); 53457e2ea2e9SAnilkumar Kolli msdu = idr_find(&rx_ring->bufs_idr, buf_id); 53467e2ea2e9SAnilkumar Kolli if (!msdu) { 53477e2ea2e9SAnilkumar Kolli ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 53487e2ea2e9SAnilkumar Kolli "full mon msdu_pop: invalid buf_id %d\n", 53497e2ea2e9SAnilkumar Kolli buf_id); 53507e2ea2e9SAnilkumar Kolli spin_unlock_bh(&rx_ring->idr_lock); 53517e2ea2e9SAnilkumar Kolli break; 53527e2ea2e9SAnilkumar Kolli } 53537e2ea2e9SAnilkumar Kolli idr_remove(&rx_ring->bufs_idr, buf_id); 53547e2ea2e9SAnilkumar Kolli spin_unlock_bh(&rx_ring->idr_lock); 53557e2ea2e9SAnilkumar Kolli 53567e2ea2e9SAnilkumar Kolli rxcb = ATH11K_SKB_RXCB(msdu); 53577e2ea2e9SAnilkumar Kolli if (!rxcb->unmapped) { 53587e2ea2e9SAnilkumar Kolli dma_unmap_single(ar->ab->dev, rxcb->paddr, 53597e2ea2e9SAnilkumar Kolli msdu->len + 53607e2ea2e9SAnilkumar Kolli skb_tailroom(msdu), 53617e2ea2e9SAnilkumar Kolli DMA_FROM_DEVICE); 53627e2ea2e9SAnilkumar Kolli rxcb->unmapped = 1; 53637e2ea2e9SAnilkumar Kolli } 53647e2ea2e9SAnilkumar Kolli if (drop_mpdu) { 53657e2ea2e9SAnilkumar Kolli ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 53667e2ea2e9SAnilkumar Kolli "full mon: i %d drop msdu %p *ppdu_id %x\n", 53677e2ea2e9SAnilkumar Kolli i, msdu, sw_mon_entries->ppdu_id); 53687e2ea2e9SAnilkumar Kolli dev_kfree_skb_any(msdu); 53697e2ea2e9SAnilkumar Kolli msdu_cnt--; 53707e2ea2e9SAnilkumar Kolli goto next_msdu; 53717e2ea2e9SAnilkumar Kolli } 53727e2ea2e9SAnilkumar Kolli 53737e2ea2e9SAnilkumar Kolli rx_desc = (struct hal_rx_desc *)msdu->data; 53747e2ea2e9SAnilkumar Kolli 53757e2ea2e9SAnilkumar Kolli rx_pkt_offset = sizeof(struct hal_rx_desc); 53767e2ea2e9SAnilkumar Kolli l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, rx_desc); 53777e2ea2e9SAnilkumar Kolli 53787e2ea2e9SAnilkumar Kolli if (is_first_msdu) { 53797e2ea2e9SAnilkumar Kolli if (!ath11k_dp_rxdesc_mpdu_valid(ar->ab, rx_desc)) { 53807e2ea2e9SAnilkumar Kolli drop_mpdu = true; 53817e2ea2e9SAnilkumar Kolli dev_kfree_skb_any(msdu); 53827e2ea2e9SAnilkumar Kolli msdu = NULL; 53837e2ea2e9SAnilkumar Kolli goto next_msdu; 53847e2ea2e9SAnilkumar Kolli } 53857e2ea2e9SAnilkumar Kolli is_first_msdu = false; 53867e2ea2e9SAnilkumar Kolli } 53877e2ea2e9SAnilkumar Kolli 53887e2ea2e9SAnilkumar Kolli ath11k_dp_mon_get_buf_len(&msdu_list.msdu_info[i], 53897e2ea2e9SAnilkumar Kolli &is_frag, &total_len, 53907e2ea2e9SAnilkumar Kolli &frag_len, &msdu_cnt); 53917e2ea2e9SAnilkumar Kolli 53927e2ea2e9SAnilkumar Kolli rx_buf_size = rx_pkt_offset + l2_hdr_offset + frag_len; 53937e2ea2e9SAnilkumar Kolli 53947e2ea2e9SAnilkumar Kolli ath11k_dp_pkt_set_pktlen(msdu, rx_buf_size); 53957e2ea2e9SAnilkumar Kolli 53967e2ea2e9SAnilkumar Kolli if (!(*head_msdu)) 53977e2ea2e9SAnilkumar Kolli *head_msdu = msdu; 53987e2ea2e9SAnilkumar Kolli else if (last) 53997e2ea2e9SAnilkumar Kolli last->next = msdu; 54007e2ea2e9SAnilkumar Kolli 54017e2ea2e9SAnilkumar Kolli last = msdu; 54027e2ea2e9SAnilkumar Kolli next_msdu: 54037e2ea2e9SAnilkumar Kolli rx_bufs_used++; 54047e2ea2e9SAnilkumar Kolli } 54057e2ea2e9SAnilkumar Kolli 54067e2ea2e9SAnilkumar Kolli ath11k_dp_rx_mon_next_link_desc_get(rx_msdu_link_desc, 54077e2ea2e9SAnilkumar Kolli &sw_mon_entries->mon_dst_paddr, 54087e2ea2e9SAnilkumar Kolli &sw_mon_entries->mon_dst_sw_cookie, 54097e2ea2e9SAnilkumar Kolli &rbm, 54107e2ea2e9SAnilkumar Kolli &p_buf_addr_info); 54117e2ea2e9SAnilkumar Kolli 54127e2ea2e9SAnilkumar Kolli if (ath11k_dp_rx_monitor_link_desc_return(ar, 54137e2ea2e9SAnilkumar Kolli p_last_buf_addr_info, 54147e2ea2e9SAnilkumar Kolli dp->mac_id)) 54157e2ea2e9SAnilkumar Kolli ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 54167e2ea2e9SAnilkumar Kolli "full mon: dp_rx_monitor_link_desc_return failed\n"); 54177e2ea2e9SAnilkumar Kolli 54187e2ea2e9SAnilkumar Kolli p_last_buf_addr_info = p_buf_addr_info; 54197e2ea2e9SAnilkumar Kolli 54207e2ea2e9SAnilkumar Kolli } while (sw_mon_entries->mon_dst_paddr && msdu_cnt); 54217e2ea2e9SAnilkumar Kolli 54227e2ea2e9SAnilkumar Kolli if (last) 54237e2ea2e9SAnilkumar Kolli last->next = NULL; 54247e2ea2e9SAnilkumar Kolli 54257e2ea2e9SAnilkumar Kolli *tail_msdu = msdu; 54267e2ea2e9SAnilkumar Kolli 54277e2ea2e9SAnilkumar Kolli return rx_bufs_used; 54287e2ea2e9SAnilkumar Kolli } 54297e2ea2e9SAnilkumar Kolli 54307e2ea2e9SAnilkumar Kolli static int ath11k_dp_rx_full_mon_prepare_mpdu(struct ath11k_dp *dp, 54317e2ea2e9SAnilkumar Kolli struct dp_full_mon_mpdu *mon_mpdu, 54327e2ea2e9SAnilkumar Kolli struct sk_buff *head, 54337e2ea2e9SAnilkumar Kolli struct sk_buff *tail) 54347e2ea2e9SAnilkumar Kolli { 54357e2ea2e9SAnilkumar Kolli mon_mpdu = kzalloc(sizeof(*mon_mpdu), GFP_ATOMIC); 54367e2ea2e9SAnilkumar Kolli if (!mon_mpdu) 54377e2ea2e9SAnilkumar Kolli return -ENOMEM; 54387e2ea2e9SAnilkumar Kolli 54397e2ea2e9SAnilkumar Kolli list_add_tail(&mon_mpdu->list, &dp->dp_full_mon_mpdu_list); 54407e2ea2e9SAnilkumar Kolli mon_mpdu->head = head; 54417e2ea2e9SAnilkumar Kolli mon_mpdu->tail = tail; 54427e2ea2e9SAnilkumar Kolli 54437e2ea2e9SAnilkumar Kolli return 0; 54447e2ea2e9SAnilkumar Kolli } 54457e2ea2e9SAnilkumar Kolli 54467e2ea2e9SAnilkumar Kolli static void ath11k_dp_rx_full_mon_drop_ppdu(struct ath11k_dp *dp, 54477e2ea2e9SAnilkumar Kolli struct dp_full_mon_mpdu *mon_mpdu) 54487e2ea2e9SAnilkumar Kolli { 54497e2ea2e9SAnilkumar Kolli struct dp_full_mon_mpdu *tmp; 54507e2ea2e9SAnilkumar Kolli struct sk_buff *tmp_msdu, *skb_next; 54517e2ea2e9SAnilkumar Kolli 54527e2ea2e9SAnilkumar Kolli if (list_empty(&dp->dp_full_mon_mpdu_list)) 54537e2ea2e9SAnilkumar Kolli return; 54547e2ea2e9SAnilkumar Kolli 54557e2ea2e9SAnilkumar Kolli list_for_each_entry_safe(mon_mpdu, tmp, &dp->dp_full_mon_mpdu_list, list) { 54567e2ea2e9SAnilkumar Kolli list_del(&mon_mpdu->list); 54577e2ea2e9SAnilkumar Kolli 54587e2ea2e9SAnilkumar Kolli tmp_msdu = mon_mpdu->head; 54597e2ea2e9SAnilkumar Kolli while (tmp_msdu) { 54607e2ea2e9SAnilkumar Kolli skb_next = tmp_msdu->next; 54617e2ea2e9SAnilkumar Kolli dev_kfree_skb_any(tmp_msdu); 54627e2ea2e9SAnilkumar Kolli tmp_msdu = skb_next; 54637e2ea2e9SAnilkumar Kolli } 54647e2ea2e9SAnilkumar Kolli 54657e2ea2e9SAnilkumar Kolli kfree(mon_mpdu); 54667e2ea2e9SAnilkumar Kolli } 54677e2ea2e9SAnilkumar Kolli } 54687e2ea2e9SAnilkumar Kolli 54697e2ea2e9SAnilkumar Kolli static int ath11k_dp_rx_full_mon_deliver_ppdu(struct ath11k *ar, 54707e2ea2e9SAnilkumar Kolli int mac_id, 54717e2ea2e9SAnilkumar Kolli struct ath11k_mon_data *pmon, 54727e2ea2e9SAnilkumar Kolli struct napi_struct *napi) 54737e2ea2e9SAnilkumar Kolli { 54747e2ea2e9SAnilkumar Kolli struct ath11k_pdev_mon_stats *rx_mon_stats; 54757e2ea2e9SAnilkumar Kolli struct dp_full_mon_mpdu *tmp; 54767e2ea2e9SAnilkumar Kolli struct dp_full_mon_mpdu *mon_mpdu = pmon->mon_mpdu; 54777e2ea2e9SAnilkumar Kolli struct sk_buff *head_msdu, *tail_msdu; 54787e2ea2e9SAnilkumar Kolli struct ath11k_base *ab = ar->ab; 54797e2ea2e9SAnilkumar Kolli struct ath11k_dp *dp = &ab->dp; 54807e2ea2e9SAnilkumar Kolli int ret; 54817e2ea2e9SAnilkumar Kolli 54827e2ea2e9SAnilkumar Kolli rx_mon_stats = &pmon->rx_mon_stats; 54837e2ea2e9SAnilkumar Kolli 54847e2ea2e9SAnilkumar Kolli list_for_each_entry_safe(mon_mpdu, tmp, &dp->dp_full_mon_mpdu_list, list) { 54857e2ea2e9SAnilkumar Kolli list_del(&mon_mpdu->list); 54867e2ea2e9SAnilkumar Kolli head_msdu = mon_mpdu->head; 54877e2ea2e9SAnilkumar Kolli tail_msdu = mon_mpdu->tail; 54887e2ea2e9SAnilkumar Kolli if (head_msdu && tail_msdu) { 54897e2ea2e9SAnilkumar Kolli ret = ath11k_dp_rx_mon_deliver(ar, mac_id, head_msdu, 549001d2f285SPradeep Kumar Chitrapu &pmon->mon_ppdu_info, 54917e2ea2e9SAnilkumar Kolli tail_msdu, napi); 54927e2ea2e9SAnilkumar Kolli rx_mon_stats->dest_mpdu_done++; 54937e2ea2e9SAnilkumar Kolli ath11k_dbg(ar->ab, ATH11K_DBG_DATA, "full mon: deliver ppdu\n"); 54947e2ea2e9SAnilkumar Kolli } 54957e2ea2e9SAnilkumar Kolli kfree(mon_mpdu); 54967e2ea2e9SAnilkumar Kolli } 54977e2ea2e9SAnilkumar Kolli 54987e2ea2e9SAnilkumar Kolli return ret; 54997e2ea2e9SAnilkumar Kolli } 55007e2ea2e9SAnilkumar Kolli 55017e2ea2e9SAnilkumar Kolli static int 55027e2ea2e9SAnilkumar Kolli ath11k_dp_rx_process_full_mon_status_ring(struct ath11k_base *ab, int mac_id, 55037e2ea2e9SAnilkumar Kolli struct napi_struct *napi, int budget) 55047e2ea2e9SAnilkumar Kolli { 55057e2ea2e9SAnilkumar Kolli struct ath11k *ar = ab->pdevs[mac_id].ar; 55067e2ea2e9SAnilkumar Kolli struct ath11k_pdev_dp *dp = &ar->dp; 55077e2ea2e9SAnilkumar Kolli struct ath11k_mon_data *pmon = &dp->mon_data; 55087e2ea2e9SAnilkumar Kolli struct hal_sw_mon_ring_entries *sw_mon_entries; 55097e2ea2e9SAnilkumar Kolli int quota = 0, work = 0, count; 55107e2ea2e9SAnilkumar Kolli 55117e2ea2e9SAnilkumar Kolli sw_mon_entries = &pmon->sw_mon_entries; 55127e2ea2e9SAnilkumar Kolli 55137e2ea2e9SAnilkumar Kolli while (pmon->hold_mon_dst_ring) { 55147e2ea2e9SAnilkumar Kolli quota = ath11k_dp_rx_process_mon_status(ab, mac_id, 55157e2ea2e9SAnilkumar Kolli napi, 1); 55167e2ea2e9SAnilkumar Kolli if (pmon->buf_state == DP_MON_STATUS_MATCH) { 55177e2ea2e9SAnilkumar Kolli count = sw_mon_entries->status_buf_count; 55187e2ea2e9SAnilkumar Kolli if (count > 1) { 55197e2ea2e9SAnilkumar Kolli quota += ath11k_dp_rx_process_mon_status(ab, mac_id, 55207e2ea2e9SAnilkumar Kolli napi, count); 55217e2ea2e9SAnilkumar Kolli } 55227e2ea2e9SAnilkumar Kolli 55237e2ea2e9SAnilkumar Kolli ath11k_dp_rx_full_mon_deliver_ppdu(ar, dp->mac_id, 55247e2ea2e9SAnilkumar Kolli pmon, napi); 55257e2ea2e9SAnilkumar Kolli pmon->hold_mon_dst_ring = false; 55267e2ea2e9SAnilkumar Kolli } else if (!pmon->mon_status_paddr || 55277e2ea2e9SAnilkumar Kolli pmon->buf_state == DP_MON_STATUS_LEAD) { 55287e2ea2e9SAnilkumar Kolli sw_mon_entries->drop_ppdu = true; 55297e2ea2e9SAnilkumar Kolli pmon->hold_mon_dst_ring = false; 55307e2ea2e9SAnilkumar Kolli } 55317e2ea2e9SAnilkumar Kolli 55327e2ea2e9SAnilkumar Kolli if (!quota) 55337e2ea2e9SAnilkumar Kolli break; 55347e2ea2e9SAnilkumar Kolli 55357e2ea2e9SAnilkumar Kolli work += quota; 55367e2ea2e9SAnilkumar Kolli } 55377e2ea2e9SAnilkumar Kolli 55387e2ea2e9SAnilkumar Kolli if (sw_mon_entries->drop_ppdu) 55397e2ea2e9SAnilkumar Kolli ath11k_dp_rx_full_mon_drop_ppdu(&ab->dp, pmon->mon_mpdu); 55407e2ea2e9SAnilkumar Kolli 55417e2ea2e9SAnilkumar Kolli return work; 55427e2ea2e9SAnilkumar Kolli } 55437e2ea2e9SAnilkumar Kolli 55447e2ea2e9SAnilkumar Kolli static int ath11k_dp_full_mon_process_rx(struct ath11k_base *ab, int mac_id, 55457e2ea2e9SAnilkumar Kolli struct napi_struct *napi, int budget) 55467e2ea2e9SAnilkumar Kolli { 55477e2ea2e9SAnilkumar Kolli struct ath11k *ar = ab->pdevs[mac_id].ar; 55487e2ea2e9SAnilkumar Kolli struct ath11k_pdev_dp *dp = &ar->dp; 55497e2ea2e9SAnilkumar Kolli struct ath11k_mon_data *pmon = &dp->mon_data; 55507e2ea2e9SAnilkumar Kolli struct hal_sw_mon_ring_entries *sw_mon_entries; 55517e2ea2e9SAnilkumar Kolli struct ath11k_pdev_mon_stats *rx_mon_stats; 55527e2ea2e9SAnilkumar Kolli struct sk_buff *head_msdu, *tail_msdu; 55537e2ea2e9SAnilkumar Kolli void *mon_dst_srng = &ar->ab->hal.srng_list[dp->rxdma_mon_dst_ring.ring_id]; 55547e2ea2e9SAnilkumar Kolli void *ring_entry; 55557e2ea2e9SAnilkumar Kolli u32 rx_bufs_used = 0, mpdu_rx_bufs_used; 55567e2ea2e9SAnilkumar Kolli int quota = 0, ret; 55577e2ea2e9SAnilkumar Kolli bool break_dst_ring = false; 55587e2ea2e9SAnilkumar Kolli 55597e2ea2e9SAnilkumar Kolli spin_lock_bh(&pmon->mon_lock); 55607e2ea2e9SAnilkumar Kolli 55617e2ea2e9SAnilkumar Kolli sw_mon_entries = &pmon->sw_mon_entries; 55627e2ea2e9SAnilkumar Kolli rx_mon_stats = &pmon->rx_mon_stats; 55637e2ea2e9SAnilkumar Kolli 55647e2ea2e9SAnilkumar Kolli if (pmon->hold_mon_dst_ring) { 55657e2ea2e9SAnilkumar Kolli spin_unlock_bh(&pmon->mon_lock); 55667e2ea2e9SAnilkumar Kolli goto reap_status_ring; 55677e2ea2e9SAnilkumar Kolli } 55687e2ea2e9SAnilkumar Kolli 55697e2ea2e9SAnilkumar Kolli ath11k_hal_srng_access_begin(ar->ab, mon_dst_srng); 55707e2ea2e9SAnilkumar Kolli while ((ring_entry = ath11k_hal_srng_dst_peek(ar->ab, mon_dst_srng))) { 55717e2ea2e9SAnilkumar Kolli head_msdu = NULL; 55727e2ea2e9SAnilkumar Kolli tail_msdu = NULL; 55737e2ea2e9SAnilkumar Kolli 55747e2ea2e9SAnilkumar Kolli mpdu_rx_bufs_used = ath11k_dp_rx_full_mon_mpdu_pop(ar, ring_entry, 55757e2ea2e9SAnilkumar Kolli &head_msdu, 55767e2ea2e9SAnilkumar Kolli &tail_msdu, 55777e2ea2e9SAnilkumar Kolli sw_mon_entries); 55787e2ea2e9SAnilkumar Kolli rx_bufs_used += mpdu_rx_bufs_used; 55797e2ea2e9SAnilkumar Kolli 55807e2ea2e9SAnilkumar Kolli if (!sw_mon_entries->end_of_ppdu) { 55817e2ea2e9SAnilkumar Kolli if (head_msdu) { 55827e2ea2e9SAnilkumar Kolli ret = ath11k_dp_rx_full_mon_prepare_mpdu(&ab->dp, 55837e2ea2e9SAnilkumar Kolli pmon->mon_mpdu, 55847e2ea2e9SAnilkumar Kolli head_msdu, 55857e2ea2e9SAnilkumar Kolli tail_msdu); 55867e2ea2e9SAnilkumar Kolli if (ret) 55877e2ea2e9SAnilkumar Kolli break_dst_ring = true; 55887e2ea2e9SAnilkumar Kolli } 55897e2ea2e9SAnilkumar Kolli 55907e2ea2e9SAnilkumar Kolli goto next_entry; 55917e2ea2e9SAnilkumar Kolli } else { 55927e2ea2e9SAnilkumar Kolli if (!sw_mon_entries->ppdu_id && 55937e2ea2e9SAnilkumar Kolli !sw_mon_entries->mon_status_paddr) { 55947e2ea2e9SAnilkumar Kolli break_dst_ring = true; 55957e2ea2e9SAnilkumar Kolli goto next_entry; 55967e2ea2e9SAnilkumar Kolli } 55977e2ea2e9SAnilkumar Kolli } 55987e2ea2e9SAnilkumar Kolli 55997e2ea2e9SAnilkumar Kolli rx_mon_stats->dest_ppdu_done++; 56007e2ea2e9SAnilkumar Kolli pmon->mon_ppdu_status = DP_PPDU_STATUS_START; 56017e2ea2e9SAnilkumar Kolli pmon->buf_state = DP_MON_STATUS_LAG; 56027e2ea2e9SAnilkumar Kolli pmon->mon_status_paddr = sw_mon_entries->mon_status_paddr; 56037e2ea2e9SAnilkumar Kolli pmon->hold_mon_dst_ring = true; 56047e2ea2e9SAnilkumar Kolli next_entry: 56057e2ea2e9SAnilkumar Kolli ring_entry = ath11k_hal_srng_dst_get_next_entry(ar->ab, 56067e2ea2e9SAnilkumar Kolli mon_dst_srng); 56077e2ea2e9SAnilkumar Kolli if (break_dst_ring) 56087e2ea2e9SAnilkumar Kolli break; 56097e2ea2e9SAnilkumar Kolli } 56107e2ea2e9SAnilkumar Kolli 56117e2ea2e9SAnilkumar Kolli ath11k_hal_srng_access_end(ar->ab, mon_dst_srng); 56127e2ea2e9SAnilkumar Kolli spin_unlock_bh(&pmon->mon_lock); 56137e2ea2e9SAnilkumar Kolli 56147e2ea2e9SAnilkumar Kolli if (rx_bufs_used) { 56157e2ea2e9SAnilkumar Kolli ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, 56167e2ea2e9SAnilkumar Kolli &dp->rxdma_mon_buf_ring, 56177e2ea2e9SAnilkumar Kolli rx_bufs_used, 56187e2ea2e9SAnilkumar Kolli HAL_RX_BUF_RBM_SW3_BM); 56197e2ea2e9SAnilkumar Kolli } 56207e2ea2e9SAnilkumar Kolli 56217e2ea2e9SAnilkumar Kolli reap_status_ring: 56227e2ea2e9SAnilkumar Kolli quota = ath11k_dp_rx_process_full_mon_status_ring(ab, mac_id, 56237e2ea2e9SAnilkumar Kolli napi, budget); 56247e2ea2e9SAnilkumar Kolli 56257e2ea2e9SAnilkumar Kolli return quota; 56267e2ea2e9SAnilkumar Kolli } 56277e2ea2e9SAnilkumar Kolli 5628d5c65159SKalle Valo int ath11k_dp_rx_process_mon_rings(struct ath11k_base *ab, int mac_id, 5629d5c65159SKalle Valo struct napi_struct *napi, int budget) 5630d5c65159SKalle Valo { 56314152e420SCarl Huang struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); 5632d5c65159SKalle Valo int ret = 0; 5633d5c65159SKalle Valo 56347e2ea2e9SAnilkumar Kolli if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags) && 56357e2ea2e9SAnilkumar Kolli ab->hw_params.full_monitor_mode) 56367e2ea2e9SAnilkumar Kolli ret = ath11k_dp_full_mon_process_rx(ab, mac_id, napi, budget); 5637d5c65159SKalle Valo else 5638d5c65159SKalle Valo ret = ath11k_dp_rx_process_mon_status(ab, mac_id, napi, budget); 56397e2ea2e9SAnilkumar Kolli 5640d5c65159SKalle Valo return ret; 5641d5c65159SKalle Valo } 5642d5c65159SKalle Valo 5643d5c65159SKalle Valo static int ath11k_dp_rx_pdev_mon_status_attach(struct ath11k *ar) 5644d5c65159SKalle Valo { 5645d5c65159SKalle Valo struct ath11k_pdev_dp *dp = &ar->dp; 5646d5c65159SKalle Valo struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data; 5647d5c65159SKalle Valo 5648d5c65159SKalle Valo skb_queue_head_init(&pmon->rx_status_q); 5649d5c65159SKalle Valo 5650d5c65159SKalle Valo pmon->mon_ppdu_status = DP_PPDU_STATUS_START; 5651d5c65159SKalle Valo 5652d5c65159SKalle Valo memset(&pmon->rx_mon_stats, 0, 5653d5c65159SKalle Valo sizeof(pmon->rx_mon_stats)); 5654d5c65159SKalle Valo return 0; 5655d5c65159SKalle Valo } 5656d5c65159SKalle Valo 5657d5c65159SKalle Valo int ath11k_dp_rx_pdev_mon_attach(struct ath11k *ar) 5658d5c65159SKalle Valo { 5659d5c65159SKalle Valo struct ath11k_pdev_dp *dp = &ar->dp; 5660d5c65159SKalle Valo struct ath11k_mon_data *pmon = &dp->mon_data; 5661d5c65159SKalle Valo struct hal_srng *mon_desc_srng = NULL; 5662d5c65159SKalle Valo struct dp_srng *dp_srng; 5663d5c65159SKalle Valo int ret = 0; 5664d5c65159SKalle Valo u32 n_link_desc = 0; 5665d5c65159SKalle Valo 5666d5c65159SKalle Valo ret = ath11k_dp_rx_pdev_mon_status_attach(ar); 5667d5c65159SKalle Valo if (ret) { 5668d5c65159SKalle Valo ath11k_warn(ar->ab, "pdev_mon_status_attach() failed"); 5669d5c65159SKalle Valo return ret; 5670d5c65159SKalle Valo } 5671d5c65159SKalle Valo 56727f6fc1ebSCarl Huang /* if rxdma1_enable is false, no need to setup 56737f6fc1ebSCarl Huang * rxdma_mon_desc_ring. 56747f6fc1ebSCarl Huang */ 56757f6fc1ebSCarl Huang if (!ar->ab->hw_params.rxdma1_enable) 56767f6fc1ebSCarl Huang return 0; 56777f6fc1ebSCarl Huang 5678d5c65159SKalle Valo dp_srng = &dp->rxdma_mon_desc_ring; 5679d5c65159SKalle Valo n_link_desc = dp_srng->size / 5680f7eb4b04SKalle Valo ath11k_hal_srng_get_entrysize(ar->ab, HAL_RXDMA_MONITOR_DESC); 5681d5c65159SKalle Valo mon_desc_srng = 5682d5c65159SKalle Valo &ar->ab->hal.srng_list[dp->rxdma_mon_desc_ring.ring_id]; 5683d5c65159SKalle Valo 5684d5c65159SKalle Valo ret = ath11k_dp_link_desc_setup(ar->ab, pmon->link_desc_banks, 5685d5c65159SKalle Valo HAL_RXDMA_MONITOR_DESC, mon_desc_srng, 5686d5c65159SKalle Valo n_link_desc); 5687d5c65159SKalle Valo if (ret) { 5688d5c65159SKalle Valo ath11k_warn(ar->ab, "mon_link_desc_pool_setup() failed"); 5689d5c65159SKalle Valo return ret; 5690d5c65159SKalle Valo } 5691d5c65159SKalle Valo pmon->mon_last_linkdesc_paddr = 0; 5692d5c65159SKalle Valo pmon->mon_last_buf_cookie = DP_RX_DESC_COOKIE_MAX + 1; 5693d5c65159SKalle Valo spin_lock_init(&pmon->mon_lock); 56947f6fc1ebSCarl Huang 5695d5c65159SKalle Valo return 0; 5696d5c65159SKalle Valo } 5697d5c65159SKalle Valo 5698d5c65159SKalle Valo static int ath11k_dp_mon_link_free(struct ath11k *ar) 5699d5c65159SKalle Valo { 5700d5c65159SKalle Valo struct ath11k_pdev_dp *dp = &ar->dp; 5701d5c65159SKalle Valo struct ath11k_mon_data *pmon = &dp->mon_data; 5702d5c65159SKalle Valo 5703d5c65159SKalle Valo ath11k_dp_link_desc_cleanup(ar->ab, pmon->link_desc_banks, 5704d5c65159SKalle Valo HAL_RXDMA_MONITOR_DESC, 5705d5c65159SKalle Valo &dp->rxdma_mon_desc_ring); 5706d5c65159SKalle Valo return 0; 5707d5c65159SKalle Valo } 5708d5c65159SKalle Valo 5709d5c65159SKalle Valo int ath11k_dp_rx_pdev_mon_detach(struct ath11k *ar) 5710d5c65159SKalle Valo { 5711d5c65159SKalle Valo ath11k_dp_mon_link_free(ar); 5712d5c65159SKalle Valo return 0; 5713d5c65159SKalle Valo } 5714840c36faSCarl Huang 5715840c36faSCarl Huang int ath11k_dp_rx_pktlog_start(struct ath11k_base *ab) 5716840c36faSCarl Huang { 5717840c36faSCarl Huang /* start reap timer */ 5718840c36faSCarl Huang mod_timer(&ab->mon_reap_timer, 5719840c36faSCarl Huang jiffies + msecs_to_jiffies(ATH11K_MON_TIMER_INTERVAL)); 5720840c36faSCarl Huang 5721840c36faSCarl Huang return 0; 5722840c36faSCarl Huang } 5723840c36faSCarl Huang 5724840c36faSCarl Huang int ath11k_dp_rx_pktlog_stop(struct ath11k_base *ab, bool stop_timer) 5725840c36faSCarl Huang { 5726840c36faSCarl Huang int ret; 5727840c36faSCarl Huang 5728840c36faSCarl Huang if (stop_timer) 5729840c36faSCarl Huang del_timer_sync(&ab->mon_reap_timer); 5730840c36faSCarl Huang 5731840c36faSCarl Huang /* reap all the monitor related rings */ 5732840c36faSCarl Huang ret = ath11k_dp_purge_mon_ring(ab); 5733840c36faSCarl Huang if (ret) { 5734840c36faSCarl Huang ath11k_warn(ab, "failed to purge dp mon ring: %d\n", ret); 5735840c36faSCarl Huang return ret; 5736840c36faSCarl Huang } 5737840c36faSCarl Huang 5738840c36faSCarl Huang return 0; 5739840c36faSCarl Huang } 5740