18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause-Clear 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/ieee80211.h> 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 98c2ecf20Sopenharmony_ci#include <crypto/hash.h> 108c2ecf20Sopenharmony_ci#include "core.h" 118c2ecf20Sopenharmony_ci#include "debug.h" 128c2ecf20Sopenharmony_ci#include "debugfs_htt_stats.h" 138c2ecf20Sopenharmony_ci#include "debugfs_sta.h" 148c2ecf20Sopenharmony_ci#include "hal_desc.h" 158c2ecf20Sopenharmony_ci#include "hw.h" 168c2ecf20Sopenharmony_ci#include "dp_rx.h" 178c2ecf20Sopenharmony_ci#include "hal_rx.h" 188c2ecf20Sopenharmony_ci#include "dp_tx.h" 198c2ecf20Sopenharmony_ci#include "peer.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define ATH11K_DP_RX_FRAGMENT_TIMEOUT_MS (2 * HZ) 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic u8 *ath11k_dp_rx_h_80211_hdr(struct hal_rx_desc *desc) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci return desc->hdr_status; 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic enum hal_encrypt_type ath11k_dp_rx_h_mpdu_start_enctype(struct hal_rx_desc *desc) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci if (!(__le32_to_cpu(desc->mpdu_start.info1) & 318c2ecf20Sopenharmony_ci RX_MPDU_START_INFO1_ENCRYPT_INFO_VALID)) 328c2ecf20Sopenharmony_ci return HAL_ENCRYPT_TYPE_OPEN; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci return FIELD_GET(RX_MPDU_START_INFO2_ENC_TYPE, 358c2ecf20Sopenharmony_ci __le32_to_cpu(desc->mpdu_start.info2)); 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic u8 ath11k_dp_rx_h_msdu_start_decap_type(struct hal_rx_desc *desc) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci return FIELD_GET(RX_MSDU_START_INFO2_DECAP_FORMAT, 418c2ecf20Sopenharmony_ci __le32_to_cpu(desc->msdu_start.info2)); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic u8 ath11k_dp_rx_h_msdu_start_mesh_ctl_present(struct hal_rx_desc *desc) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci return FIELD_GET(RX_MSDU_START_INFO2_MESH_CTRL_PRESENT, 478c2ecf20Sopenharmony_ci __le32_to_cpu(desc->msdu_start.info2)); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_mpdu_start_seq_ctrl_valid(struct hal_rx_desc *desc) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci return !!FIELD_GET(RX_MPDU_START_INFO1_MPDU_SEQ_CTRL_VALID, 538c2ecf20Sopenharmony_ci __le32_to_cpu(desc->mpdu_start.info1)); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_mpdu_start_fc_valid(struct hal_rx_desc *desc) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci return !!FIELD_GET(RX_MPDU_START_INFO1_MPDU_FCTRL_VALID, 598c2ecf20Sopenharmony_ci __le32_to_cpu(desc->mpdu_start.info1)); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_mpdu_start_more_frags(struct sk_buff *skb) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)(skb->data + HAL_RX_DESC_SIZE); 678c2ecf20Sopenharmony_ci return ieee80211_has_morefrags(hdr->frame_control); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic u16 ath11k_dp_rx_h_mpdu_start_frag_no(struct sk_buff *skb) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)(skb->data + HAL_RX_DESC_SIZE); 758c2ecf20Sopenharmony_ci return le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic u16 ath11k_dp_rx_h_mpdu_start_seq_no(struct hal_rx_desc *desc) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci return FIELD_GET(RX_MPDU_START_INFO1_MPDU_SEQ_NUM, 818c2ecf20Sopenharmony_ci __le32_to_cpu(desc->mpdu_start.info1)); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_attn_msdu_done(struct hal_rx_desc *desc) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci return !!FIELD_GET(RX_ATTENTION_INFO2_MSDU_DONE, 878c2ecf20Sopenharmony_ci __le32_to_cpu(desc->attention.info2)); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_attn_l4_cksum_fail(struct hal_rx_desc *desc) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci return !!FIELD_GET(RX_ATTENTION_INFO1_TCP_UDP_CKSUM_FAIL, 938c2ecf20Sopenharmony_ci __le32_to_cpu(desc->attention.info1)); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_attn_ip_cksum_fail(struct hal_rx_desc *desc) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci return !!FIELD_GET(RX_ATTENTION_INFO1_IP_CKSUM_FAIL, 998c2ecf20Sopenharmony_ci __le32_to_cpu(desc->attention.info1)); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_attn_is_decrypted(struct hal_rx_desc *desc) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci return (FIELD_GET(RX_ATTENTION_INFO2_DCRYPT_STATUS_CODE, 1058c2ecf20Sopenharmony_ci __le32_to_cpu(desc->attention.info2)) == 1068c2ecf20Sopenharmony_ci RX_DESC_DECRYPT_STATUS_CODE_OK); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic u32 ath11k_dp_rx_h_attn_mpdu_err(struct hal_rx_desc *desc) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci u32 info = __le32_to_cpu(desc->attention.info1); 1128c2ecf20Sopenharmony_ci u32 errmap = 0; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (info & RX_ATTENTION_INFO1_FCS_ERR) 1158c2ecf20Sopenharmony_ci errmap |= DP_RX_MPDU_ERR_FCS; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (info & RX_ATTENTION_INFO1_DECRYPT_ERR) 1188c2ecf20Sopenharmony_ci errmap |= DP_RX_MPDU_ERR_DECRYPT; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (info & RX_ATTENTION_INFO1_TKIP_MIC_ERR) 1218c2ecf20Sopenharmony_ci errmap |= DP_RX_MPDU_ERR_TKIP_MIC; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (info & RX_ATTENTION_INFO1_A_MSDU_ERROR) 1248c2ecf20Sopenharmony_ci errmap |= DP_RX_MPDU_ERR_AMSDU_ERR; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (info & RX_ATTENTION_INFO1_OVERFLOW_ERR) 1278c2ecf20Sopenharmony_ci errmap |= DP_RX_MPDU_ERR_OVERFLOW; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (info & RX_ATTENTION_INFO1_MSDU_LEN_ERR) 1308c2ecf20Sopenharmony_ci errmap |= DP_RX_MPDU_ERR_MSDU_LEN; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (info & RX_ATTENTION_INFO1_MPDU_LEN_ERR) 1338c2ecf20Sopenharmony_ci errmap |= DP_RX_MPDU_ERR_MPDU_LEN; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return errmap; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic u16 ath11k_dp_rx_h_msdu_start_msdu_len(struct hal_rx_desc *desc) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci return FIELD_GET(RX_MSDU_START_INFO1_MSDU_LENGTH, 1418c2ecf20Sopenharmony_ci __le32_to_cpu(desc->msdu_start.info1)); 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic u8 ath11k_dp_rx_h_msdu_start_sgi(struct hal_rx_desc *desc) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci return FIELD_GET(RX_MSDU_START_INFO3_SGI, 1478c2ecf20Sopenharmony_ci __le32_to_cpu(desc->msdu_start.info3)); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic u8 ath11k_dp_rx_h_msdu_start_rate_mcs(struct hal_rx_desc *desc) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci return FIELD_GET(RX_MSDU_START_INFO3_RATE_MCS, 1538c2ecf20Sopenharmony_ci __le32_to_cpu(desc->msdu_start.info3)); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic u8 ath11k_dp_rx_h_msdu_start_rx_bw(struct hal_rx_desc *desc) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci return FIELD_GET(RX_MSDU_START_INFO3_RECV_BW, 1598c2ecf20Sopenharmony_ci __le32_to_cpu(desc->msdu_start.info3)); 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic u32 ath11k_dp_rx_h_msdu_start_freq(struct hal_rx_desc *desc) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci return __le32_to_cpu(desc->msdu_start.phy_meta_data); 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic u8 ath11k_dp_rx_h_msdu_start_pkt_type(struct hal_rx_desc *desc) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci return FIELD_GET(RX_MSDU_START_INFO3_PKT_TYPE, 1708c2ecf20Sopenharmony_ci __le32_to_cpu(desc->msdu_start.info3)); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic u8 ath11k_dp_rx_h_msdu_start_nss(struct hal_rx_desc *desc) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci u8 mimo_ss_bitmap = FIELD_GET(RX_MSDU_START_INFO3_MIMO_SS_BITMAP, 1768c2ecf20Sopenharmony_ci __le32_to_cpu(desc->msdu_start.info3)); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return hweight8(mimo_ss_bitmap); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic u8 ath11k_dp_rx_h_mpdu_start_tid(struct hal_rx_desc *desc) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci return FIELD_GET(RX_MPDU_START_INFO2_TID, 1848c2ecf20Sopenharmony_ci __le32_to_cpu(desc->mpdu_start.info2)); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic u16 ath11k_dp_rx_h_mpdu_start_peer_id(struct hal_rx_desc *desc) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci return __le16_to_cpu(desc->mpdu_start.sw_peer_id); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic u8 ath11k_dp_rx_h_msdu_end_l3pad(struct hal_rx_desc *desc) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci return FIELD_GET(RX_MSDU_END_INFO2_L3_HDR_PADDING, 1958c2ecf20Sopenharmony_ci __le32_to_cpu(desc->msdu_end.info2)); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_msdu_end_first_msdu(struct hal_rx_desc *desc) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci return !!FIELD_GET(RX_MSDU_END_INFO2_FIRST_MSDU, 2018c2ecf20Sopenharmony_ci __le32_to_cpu(desc->msdu_end.info2)); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_msdu_end_last_msdu(struct hal_rx_desc *desc) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci return !!FIELD_GET(RX_MSDU_END_INFO2_LAST_MSDU, 2078c2ecf20Sopenharmony_ci __le32_to_cpu(desc->msdu_end.info2)); 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_desc_end_tlv_copy(struct hal_rx_desc *fdesc, 2118c2ecf20Sopenharmony_ci struct hal_rx_desc *ldesc) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci memcpy((u8 *)&fdesc->msdu_end, (u8 *)&ldesc->msdu_end, 2148c2ecf20Sopenharmony_ci sizeof(struct rx_msdu_end)); 2158c2ecf20Sopenharmony_ci memcpy((u8 *)&fdesc->attention, (u8 *)&ldesc->attention, 2168c2ecf20Sopenharmony_ci sizeof(struct rx_attention)); 2178c2ecf20Sopenharmony_ci memcpy((u8 *)&fdesc->mpdu_end, (u8 *)&ldesc->mpdu_end, 2188c2ecf20Sopenharmony_ci sizeof(struct rx_mpdu_end)); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic u32 ath11k_dp_rxdesc_get_mpdulen_err(struct hal_rx_desc *rx_desc) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct rx_attention *rx_attn; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci rx_attn = &rx_desc->attention; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return FIELD_GET(RX_ATTENTION_INFO1_MPDU_LEN_ERR, 2288c2ecf20Sopenharmony_ci __le32_to_cpu(rx_attn->info1)); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic u32 ath11k_dp_rxdesc_get_decap_format(struct hal_rx_desc *rx_desc) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct rx_msdu_start *rx_msdu_start; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci rx_msdu_start = &rx_desc->msdu_start; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return FIELD_GET(RX_MSDU_START_INFO2_DECAP_FORMAT, 2388c2ecf20Sopenharmony_ci __le32_to_cpu(rx_msdu_start->info2)); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic u8 *ath11k_dp_rxdesc_get_80211hdr(struct hal_rx_desc *rx_desc) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci u8 *rx_pkt_hdr; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci rx_pkt_hdr = &rx_desc->msdu_payload[0]; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return rx_pkt_hdr; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic bool ath11k_dp_rxdesc_mpdu_valid(struct hal_rx_desc *rx_desc) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci u32 tlv_tag; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci tlv_tag = FIELD_GET(HAL_TLV_HDR_TAG, 2558c2ecf20Sopenharmony_ci __le32_to_cpu(rx_desc->mpdu_start_tag)); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return tlv_tag == HAL_RX_MPDU_START; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic u32 ath11k_dp_rxdesc_get_ppduid(struct hal_rx_desc *rx_desc) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci return __le16_to_cpu(rx_desc->mpdu_start.phy_ppdu_id); 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic void ath11k_dp_service_mon_ring(struct timer_list *t) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci struct ath11k_base *ab = from_timer(ab, t, mon_reap_timer); 2688c2ecf20Sopenharmony_ci int i; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) 2718c2ecf20Sopenharmony_ci ath11k_dp_rx_process_mon_rings(ab, i, NULL, DP_MON_SERVICE_BUDGET); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci mod_timer(&ab->mon_reap_timer, jiffies + 2748c2ecf20Sopenharmony_ci msecs_to_jiffies(ATH11K_MON_TIMER_INTERVAL)); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci/* Returns number of Rx buffers replenished */ 2788c2ecf20Sopenharmony_ciint ath11k_dp_rxbufs_replenish(struct ath11k_base *ab, int mac_id, 2798c2ecf20Sopenharmony_ci struct dp_rxdma_ring *rx_ring, 2808c2ecf20Sopenharmony_ci int req_entries, 2818c2ecf20Sopenharmony_ci enum hal_rx_buf_return_buf_manager mgr) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct hal_srng *srng; 2848c2ecf20Sopenharmony_ci u32 *desc; 2858c2ecf20Sopenharmony_ci struct sk_buff *skb; 2868c2ecf20Sopenharmony_ci int num_free; 2878c2ecf20Sopenharmony_ci int num_remain; 2888c2ecf20Sopenharmony_ci int buf_id; 2898c2ecf20Sopenharmony_ci u32 cookie; 2908c2ecf20Sopenharmony_ci dma_addr_t paddr; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci req_entries = min(req_entries, rx_ring->bufs_max); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci srng = &ab->hal.srng_list[rx_ring->refill_buf_ring.ring_id]; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci spin_lock_bh(&srng->lock); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci ath11k_hal_srng_access_begin(ab, srng); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci num_free = ath11k_hal_srng_src_num_free(ab, srng, true); 3018c2ecf20Sopenharmony_ci if (!req_entries && (num_free > (rx_ring->bufs_max * 3) / 4)) 3028c2ecf20Sopenharmony_ci req_entries = num_free; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci req_entries = min(num_free, req_entries); 3058c2ecf20Sopenharmony_ci num_remain = req_entries; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci while (num_remain > 0) { 3088c2ecf20Sopenharmony_ci skb = dev_alloc_skb(DP_RX_BUFFER_SIZE + 3098c2ecf20Sopenharmony_ci DP_RX_BUFFER_ALIGN_SIZE); 3108c2ecf20Sopenharmony_ci if (!skb) 3118c2ecf20Sopenharmony_ci break; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (!IS_ALIGNED((unsigned long)skb->data, 3148c2ecf20Sopenharmony_ci DP_RX_BUFFER_ALIGN_SIZE)) { 3158c2ecf20Sopenharmony_ci skb_pull(skb, 3168c2ecf20Sopenharmony_ci PTR_ALIGN(skb->data, DP_RX_BUFFER_ALIGN_SIZE) - 3178c2ecf20Sopenharmony_ci skb->data); 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci paddr = dma_map_single(ab->dev, skb->data, 3218c2ecf20Sopenharmony_ci skb->len + skb_tailroom(skb), 3228c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 3238c2ecf20Sopenharmony_ci if (dma_mapping_error(ab->dev, paddr)) 3248c2ecf20Sopenharmony_ci goto fail_free_skb; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci spin_lock_bh(&rx_ring->idr_lock); 3278c2ecf20Sopenharmony_ci buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 1, 3288c2ecf20Sopenharmony_ci (rx_ring->bufs_max * 3) + 1, GFP_ATOMIC); 3298c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 3308c2ecf20Sopenharmony_ci if (buf_id <= 0) 3318c2ecf20Sopenharmony_ci goto fail_dma_unmap; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci desc = ath11k_hal_srng_src_get_next_entry(ab, srng); 3348c2ecf20Sopenharmony_ci if (!desc) 3358c2ecf20Sopenharmony_ci goto fail_idr_remove; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci ATH11K_SKB_RXCB(skb)->paddr = paddr; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, mac_id) | 3408c2ecf20Sopenharmony_ci FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci num_remain--; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci ath11k_hal_rx_buf_addr_info_set(desc, paddr, cookie, mgr); 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci spin_unlock_bh(&srng->lock); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return req_entries - num_remain; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cifail_idr_remove: 3548c2ecf20Sopenharmony_ci spin_lock_bh(&rx_ring->idr_lock); 3558c2ecf20Sopenharmony_ci idr_remove(&rx_ring->bufs_idr, buf_id); 3568c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 3578c2ecf20Sopenharmony_cifail_dma_unmap: 3588c2ecf20Sopenharmony_ci dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb), 3598c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 3608c2ecf20Sopenharmony_cifail_free_skb: 3618c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci spin_unlock_bh(&srng->lock); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return req_entries - num_remain; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int ath11k_dp_rxdma_buf_ring_free(struct ath11k *ar, 3718c2ecf20Sopenharmony_ci struct dp_rxdma_ring *rx_ring) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp = &ar->dp; 3748c2ecf20Sopenharmony_ci struct sk_buff *skb; 3758c2ecf20Sopenharmony_ci int buf_id; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci spin_lock_bh(&rx_ring->idr_lock); 3788c2ecf20Sopenharmony_ci idr_for_each_entry(&rx_ring->bufs_idr, skb, buf_id) { 3798c2ecf20Sopenharmony_ci idr_remove(&rx_ring->bufs_idr, buf_id); 3808c2ecf20Sopenharmony_ci /* TODO: Understand where internal driver does this dma_unmap of 3818c2ecf20Sopenharmony_ci * of rxdma_buffer. 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ci dma_unmap_single(ar->ab->dev, ATH11K_SKB_RXCB(skb)->paddr, 3848c2ecf20Sopenharmony_ci skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); 3858c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci idr_destroy(&rx_ring->bufs_idr); 3898c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* if rxdma1_enable is false, mon_status_refill_ring 3928c2ecf20Sopenharmony_ci * isn't setup, so don't clean. 3938c2ecf20Sopenharmony_ci */ 3948c2ecf20Sopenharmony_ci if (!ar->ab->hw_params.rxdma1_enable) 3958c2ecf20Sopenharmony_ci return 0; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci rx_ring = &dp->rx_mon_status_refill_ring[0]; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci spin_lock_bh(&rx_ring->idr_lock); 4008c2ecf20Sopenharmony_ci idr_for_each_entry(&rx_ring->bufs_idr, skb, buf_id) { 4018c2ecf20Sopenharmony_ci idr_remove(&rx_ring->bufs_idr, buf_id); 4028c2ecf20Sopenharmony_ci /* XXX: Understand where internal driver does this dma_unmap of 4038c2ecf20Sopenharmony_ci * of rxdma_buffer. 4048c2ecf20Sopenharmony_ci */ 4058c2ecf20Sopenharmony_ci dma_unmap_single(ar->ab->dev, ATH11K_SKB_RXCB(skb)->paddr, 4068c2ecf20Sopenharmony_ci skb->len + skb_tailroom(skb), DMA_BIDIRECTIONAL); 4078c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci idr_destroy(&rx_ring->bufs_idr); 4118c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci return 0; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic int ath11k_dp_rxdma_pdev_buf_free(struct ath11k *ar) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp = &ar->dp; 4198c2ecf20Sopenharmony_ci struct ath11k_base *ab = ar->ab; 4208c2ecf20Sopenharmony_ci struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; 4218c2ecf20Sopenharmony_ci int i; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci ath11k_dp_rxdma_buf_ring_free(ar, rx_ring); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci rx_ring = &dp->rxdma_mon_buf_ring; 4268c2ecf20Sopenharmony_ci ath11k_dp_rxdma_buf_ring_free(ar, rx_ring); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { 4298c2ecf20Sopenharmony_ci rx_ring = &dp->rx_mon_status_refill_ring[i]; 4308c2ecf20Sopenharmony_ci ath11k_dp_rxdma_buf_ring_free(ar, rx_ring); 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci return 0; 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic int ath11k_dp_rxdma_ring_buf_setup(struct ath11k *ar, 4378c2ecf20Sopenharmony_ci struct dp_rxdma_ring *rx_ring, 4388c2ecf20Sopenharmony_ci u32 ringtype) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp = &ar->dp; 4418c2ecf20Sopenharmony_ci int num_entries; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci num_entries = rx_ring->refill_buf_ring.size / 4448c2ecf20Sopenharmony_ci ath11k_hal_srng_get_entrysize(ar->ab, ringtype); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci rx_ring->bufs_max = num_entries; 4478c2ecf20Sopenharmony_ci ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, rx_ring, num_entries, 4488c2ecf20Sopenharmony_ci HAL_RX_BUF_RBM_SW3_BM); 4498c2ecf20Sopenharmony_ci return 0; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic int ath11k_dp_rxdma_pdev_buf_setup(struct ath11k *ar) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp = &ar->dp; 4558c2ecf20Sopenharmony_ci struct ath11k_base *ab = ar->ab; 4568c2ecf20Sopenharmony_ci struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; 4578c2ecf20Sopenharmony_ci int i; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_BUF); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (ar->ab->hw_params.rxdma1_enable) { 4628c2ecf20Sopenharmony_ci rx_ring = &dp->rxdma_mon_buf_ring; 4638c2ecf20Sopenharmony_ci ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_BUF); 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { 4678c2ecf20Sopenharmony_ci rx_ring = &dp->rx_mon_status_refill_ring[i]; 4688c2ecf20Sopenharmony_ci ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_STATUS); 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci return 0; 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_pdev_srng_free(struct ath11k *ar) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp = &ar->dp; 4778c2ecf20Sopenharmony_ci struct ath11k_base *ab = ar->ab; 4788c2ecf20Sopenharmony_ci int i; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci ath11k_dp_srng_cleanup(ab, &dp->rx_refill_buf_ring.refill_buf_ring); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { 4838c2ecf20Sopenharmony_ci if (ab->hw_params.rx_mac_buf_ring) 4848c2ecf20Sopenharmony_ci ath11k_dp_srng_cleanup(ab, &dp->rx_mac_buf_ring[i]); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci ath11k_dp_srng_cleanup(ab, &dp->rxdma_err_dst_ring[i]); 4878c2ecf20Sopenharmony_ci ath11k_dp_srng_cleanup(ab, 4888c2ecf20Sopenharmony_ci &dp->rx_mon_status_refill_ring[i].refill_buf_ring); 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci ath11k_dp_srng_cleanup(ab, &dp->rxdma_mon_buf_ring.refill_buf_ring); 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_civoid ath11k_dp_pdev_reo_cleanup(struct ath11k_base *ab) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct ath11k_dp *dp = &ab->dp; 4978c2ecf20Sopenharmony_ci int i; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci for (i = 0; i < DP_REO_DST_RING_MAX; i++) 5008c2ecf20Sopenharmony_ci ath11k_dp_srng_cleanup(ab, &dp->reo_dst_ring[i]); 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ciint ath11k_dp_pdev_reo_setup(struct ath11k_base *ab) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci struct ath11k_dp *dp = &ab->dp; 5068c2ecf20Sopenharmony_ci int ret; 5078c2ecf20Sopenharmony_ci int i; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci for (i = 0; i < DP_REO_DST_RING_MAX; i++) { 5108c2ecf20Sopenharmony_ci ret = ath11k_dp_srng_setup(ab, &dp->reo_dst_ring[i], 5118c2ecf20Sopenharmony_ci HAL_REO_DST, i, 0, 5128c2ecf20Sopenharmony_ci DP_REO_DST_RING_SIZE); 5138c2ecf20Sopenharmony_ci if (ret) { 5148c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to setup reo_dst_ring\n"); 5158c2ecf20Sopenharmony_ci goto err_reo_cleanup; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci return 0; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cierr_reo_cleanup: 5228c2ecf20Sopenharmony_ci ath11k_dp_pdev_reo_cleanup(ab); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci return ret; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_pdev_srng_alloc(struct ath11k *ar) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp = &ar->dp; 5308c2ecf20Sopenharmony_ci struct ath11k_base *ab = ar->ab; 5318c2ecf20Sopenharmony_ci struct dp_srng *srng = NULL; 5328c2ecf20Sopenharmony_ci int i; 5338c2ecf20Sopenharmony_ci int ret; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci ret = ath11k_dp_srng_setup(ar->ab, 5368c2ecf20Sopenharmony_ci &dp->rx_refill_buf_ring.refill_buf_ring, 5378c2ecf20Sopenharmony_ci HAL_RXDMA_BUF, 0, 5388c2ecf20Sopenharmony_ci dp->mac_id, DP_RXDMA_BUF_RING_SIZE); 5398c2ecf20Sopenharmony_ci if (ret) { 5408c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "failed to setup rx_refill_buf_ring\n"); 5418c2ecf20Sopenharmony_ci return ret; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci if (ar->ab->hw_params.rx_mac_buf_ring) { 5458c2ecf20Sopenharmony_ci for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { 5468c2ecf20Sopenharmony_ci ret = ath11k_dp_srng_setup(ar->ab, 5478c2ecf20Sopenharmony_ci &dp->rx_mac_buf_ring[i], 5488c2ecf20Sopenharmony_ci HAL_RXDMA_BUF, 1, 5498c2ecf20Sopenharmony_ci dp->mac_id + i, 1024); 5508c2ecf20Sopenharmony_ci if (ret) { 5518c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "failed to setup rx_mac_buf_ring %d\n", 5528c2ecf20Sopenharmony_ci i); 5538c2ecf20Sopenharmony_ci return ret; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { 5598c2ecf20Sopenharmony_ci ret = ath11k_dp_srng_setup(ar->ab, &dp->rxdma_err_dst_ring[i], 5608c2ecf20Sopenharmony_ci HAL_RXDMA_DST, 0, dp->mac_id + i, 5618c2ecf20Sopenharmony_ci DP_RXDMA_ERR_DST_RING_SIZE); 5628c2ecf20Sopenharmony_ci if (ret) { 5638c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "failed to setup rxdma_err_dst_ring %d\n", i); 5648c2ecf20Sopenharmony_ci return ret; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { 5698c2ecf20Sopenharmony_ci srng = &dp->rx_mon_status_refill_ring[i].refill_buf_ring; 5708c2ecf20Sopenharmony_ci ret = ath11k_dp_srng_setup(ar->ab, 5718c2ecf20Sopenharmony_ci srng, 5728c2ecf20Sopenharmony_ci HAL_RXDMA_MONITOR_STATUS, 0, dp->mac_id + i, 5738c2ecf20Sopenharmony_ci DP_RXDMA_MON_STATUS_RING_SIZE); 5748c2ecf20Sopenharmony_ci if (ret) { 5758c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, 5768c2ecf20Sopenharmony_ci "failed to setup rx_mon_status_refill_ring %d\n", i); 5778c2ecf20Sopenharmony_ci return ret; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci /* if rxdma1_enable is false, then it doesn't need 5828c2ecf20Sopenharmony_ci * to setup rxdam_mon_buf_ring, rxdma_mon_dst_ring 5838c2ecf20Sopenharmony_ci * and rxdma_mon_desc_ring. 5848c2ecf20Sopenharmony_ci * init reap timer for QCA6390. 5858c2ecf20Sopenharmony_ci */ 5868c2ecf20Sopenharmony_ci if (!ar->ab->hw_params.rxdma1_enable) { 5878c2ecf20Sopenharmony_ci //init mon status buffer reap timer 5888c2ecf20Sopenharmony_ci timer_setup(&ar->ab->mon_reap_timer, 5898c2ecf20Sopenharmony_ci ath11k_dp_service_mon_ring, 0); 5908c2ecf20Sopenharmony_ci return 0; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci ret = ath11k_dp_srng_setup(ar->ab, 5948c2ecf20Sopenharmony_ci &dp->rxdma_mon_buf_ring.refill_buf_ring, 5958c2ecf20Sopenharmony_ci HAL_RXDMA_MONITOR_BUF, 0, dp->mac_id, 5968c2ecf20Sopenharmony_ci DP_RXDMA_MONITOR_BUF_RING_SIZE); 5978c2ecf20Sopenharmony_ci if (ret) { 5988c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, 5998c2ecf20Sopenharmony_ci "failed to setup HAL_RXDMA_MONITOR_BUF\n"); 6008c2ecf20Sopenharmony_ci return ret; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci ret = ath11k_dp_srng_setup(ar->ab, &dp->rxdma_mon_dst_ring, 6048c2ecf20Sopenharmony_ci HAL_RXDMA_MONITOR_DST, 0, dp->mac_id, 6058c2ecf20Sopenharmony_ci DP_RXDMA_MONITOR_DST_RING_SIZE); 6068c2ecf20Sopenharmony_ci if (ret) { 6078c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, 6088c2ecf20Sopenharmony_ci "failed to setup HAL_RXDMA_MONITOR_DST\n"); 6098c2ecf20Sopenharmony_ci return ret; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci ret = ath11k_dp_srng_setup(ar->ab, &dp->rxdma_mon_desc_ring, 6138c2ecf20Sopenharmony_ci HAL_RXDMA_MONITOR_DESC, 0, dp->mac_id, 6148c2ecf20Sopenharmony_ci DP_RXDMA_MONITOR_DESC_RING_SIZE); 6158c2ecf20Sopenharmony_ci if (ret) { 6168c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, 6178c2ecf20Sopenharmony_ci "failed to setup HAL_RXDMA_MONITOR_DESC\n"); 6188c2ecf20Sopenharmony_ci return ret; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci return 0; 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_civoid ath11k_dp_reo_cmd_list_cleanup(struct ath11k_base *ab) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci struct ath11k_dp *dp = &ab->dp; 6278c2ecf20Sopenharmony_ci struct dp_reo_cmd *cmd, *tmp; 6288c2ecf20Sopenharmony_ci struct dp_reo_cache_flush_elem *cmd_cache, *tmp_cache; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci spin_lock_bh(&dp->reo_cmd_lock); 6318c2ecf20Sopenharmony_ci list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) { 6328c2ecf20Sopenharmony_ci list_del(&cmd->list); 6338c2ecf20Sopenharmony_ci dma_unmap_single(ab->dev, cmd->data.paddr, 6348c2ecf20Sopenharmony_ci cmd->data.size, DMA_BIDIRECTIONAL); 6358c2ecf20Sopenharmony_ci kfree(cmd->data.vaddr); 6368c2ecf20Sopenharmony_ci kfree(cmd); 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci list_for_each_entry_safe(cmd_cache, tmp_cache, 6408c2ecf20Sopenharmony_ci &dp->reo_cmd_cache_flush_list, list) { 6418c2ecf20Sopenharmony_ci list_del(&cmd_cache->list); 6428c2ecf20Sopenharmony_ci dp->reo_cmd_cache_flush_count--; 6438c2ecf20Sopenharmony_ci dma_unmap_single(ab->dev, cmd_cache->data.paddr, 6448c2ecf20Sopenharmony_ci cmd_cache->data.size, DMA_BIDIRECTIONAL); 6458c2ecf20Sopenharmony_ci kfree(cmd_cache->data.vaddr); 6468c2ecf20Sopenharmony_ci kfree(cmd_cache); 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci spin_unlock_bh(&dp->reo_cmd_lock); 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic void ath11k_dp_reo_cmd_free(struct ath11k_dp *dp, void *ctx, 6528c2ecf20Sopenharmony_ci enum hal_reo_cmd_status status) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci struct dp_rx_tid *rx_tid = ctx; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci if (status != HAL_REO_CMD_SUCCESS) 6578c2ecf20Sopenharmony_ci ath11k_warn(dp->ab, "failed to flush rx tid hw desc, tid %d status %d\n", 6588c2ecf20Sopenharmony_ci rx_tid->tid, status); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size, 6618c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 6628c2ecf20Sopenharmony_ci kfree(rx_tid->vaddr); 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cistatic void ath11k_dp_reo_cache_flush(struct ath11k_base *ab, 6668c2ecf20Sopenharmony_ci struct dp_rx_tid *rx_tid) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci struct ath11k_hal_reo_cmd cmd = {0}; 6698c2ecf20Sopenharmony_ci unsigned long tot_desc_sz, desc_sz; 6708c2ecf20Sopenharmony_ci int ret; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci tot_desc_sz = rx_tid->size; 6738c2ecf20Sopenharmony_ci desc_sz = ath11k_hal_reo_qdesc_size(0, HAL_DESC_REO_NON_QOS_TID); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci while (tot_desc_sz > desc_sz) { 6768c2ecf20Sopenharmony_ci tot_desc_sz -= desc_sz; 6778c2ecf20Sopenharmony_ci cmd.addr_lo = lower_32_bits(rx_tid->paddr + tot_desc_sz); 6788c2ecf20Sopenharmony_ci cmd.addr_hi = upper_32_bits(rx_tid->paddr); 6798c2ecf20Sopenharmony_ci ret = ath11k_dp_tx_send_reo_cmd(ab, rx_tid, 6808c2ecf20Sopenharmony_ci HAL_REO_CMD_FLUSH_CACHE, &cmd, 6818c2ecf20Sopenharmony_ci NULL); 6828c2ecf20Sopenharmony_ci if (ret) 6838c2ecf20Sopenharmony_ci ath11k_warn(ab, 6848c2ecf20Sopenharmony_ci "failed to send HAL_REO_CMD_FLUSH_CACHE, tid %d (%d)\n", 6858c2ecf20Sopenharmony_ci rx_tid->tid, ret); 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 6898c2ecf20Sopenharmony_ci cmd.addr_lo = lower_32_bits(rx_tid->paddr); 6908c2ecf20Sopenharmony_ci cmd.addr_hi = upper_32_bits(rx_tid->paddr); 6918c2ecf20Sopenharmony_ci cmd.flag |= HAL_REO_CMD_FLG_NEED_STATUS; 6928c2ecf20Sopenharmony_ci ret = ath11k_dp_tx_send_reo_cmd(ab, rx_tid, 6938c2ecf20Sopenharmony_ci HAL_REO_CMD_FLUSH_CACHE, 6948c2ecf20Sopenharmony_ci &cmd, ath11k_dp_reo_cmd_free); 6958c2ecf20Sopenharmony_ci if (ret) { 6968c2ecf20Sopenharmony_ci ath11k_err(ab, "failed to send HAL_REO_CMD_FLUSH_CACHE cmd, tid %d (%d)\n", 6978c2ecf20Sopenharmony_ci rx_tid->tid, ret); 6988c2ecf20Sopenharmony_ci dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size, 6998c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 7008c2ecf20Sopenharmony_ci kfree(rx_tid->vaddr); 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_tid_del_func(struct ath11k_dp *dp, void *ctx, 7058c2ecf20Sopenharmony_ci enum hal_reo_cmd_status status) 7068c2ecf20Sopenharmony_ci{ 7078c2ecf20Sopenharmony_ci struct ath11k_base *ab = dp->ab; 7088c2ecf20Sopenharmony_ci struct dp_rx_tid *rx_tid = ctx; 7098c2ecf20Sopenharmony_ci struct dp_reo_cache_flush_elem *elem, *tmp; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (status == HAL_REO_CMD_DRAIN) { 7128c2ecf20Sopenharmony_ci goto free_desc; 7138c2ecf20Sopenharmony_ci } else if (status != HAL_REO_CMD_SUCCESS) { 7148c2ecf20Sopenharmony_ci /* Shouldn't happen! Cleanup in case of other failure? */ 7158c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to delete rx tid %d hw descriptor %d\n", 7168c2ecf20Sopenharmony_ci rx_tid->tid, status); 7178c2ecf20Sopenharmony_ci return; 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci elem = kzalloc(sizeof(*elem), GFP_ATOMIC); 7218c2ecf20Sopenharmony_ci if (!elem) 7228c2ecf20Sopenharmony_ci goto free_desc; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci elem->ts = jiffies; 7258c2ecf20Sopenharmony_ci memcpy(&elem->data, rx_tid, sizeof(*rx_tid)); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci spin_lock_bh(&dp->reo_cmd_lock); 7288c2ecf20Sopenharmony_ci list_add_tail(&elem->list, &dp->reo_cmd_cache_flush_list); 7298c2ecf20Sopenharmony_ci dp->reo_cmd_cache_flush_count++; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* Flush and invalidate aged REO desc from HW cache */ 7328c2ecf20Sopenharmony_ci list_for_each_entry_safe(elem, tmp, &dp->reo_cmd_cache_flush_list, 7338c2ecf20Sopenharmony_ci list) { 7348c2ecf20Sopenharmony_ci if (dp->reo_cmd_cache_flush_count > DP_REO_DESC_FREE_THRESHOLD || 7358c2ecf20Sopenharmony_ci time_after(jiffies, elem->ts + 7368c2ecf20Sopenharmony_ci msecs_to_jiffies(DP_REO_DESC_FREE_TIMEOUT_MS))) { 7378c2ecf20Sopenharmony_ci list_del(&elem->list); 7388c2ecf20Sopenharmony_ci dp->reo_cmd_cache_flush_count--; 7398c2ecf20Sopenharmony_ci spin_unlock_bh(&dp->reo_cmd_lock); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci ath11k_dp_reo_cache_flush(ab, &elem->data); 7428c2ecf20Sopenharmony_ci kfree(elem); 7438c2ecf20Sopenharmony_ci spin_lock_bh(&dp->reo_cmd_lock); 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci spin_unlock_bh(&dp->reo_cmd_lock); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci return; 7498c2ecf20Sopenharmony_cifree_desc: 7508c2ecf20Sopenharmony_ci dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size, 7518c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 7528c2ecf20Sopenharmony_ci kfree(rx_tid->vaddr); 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_civoid ath11k_peer_rx_tid_delete(struct ath11k *ar, 7568c2ecf20Sopenharmony_ci struct ath11k_peer *peer, u8 tid) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci struct ath11k_hal_reo_cmd cmd = {0}; 7598c2ecf20Sopenharmony_ci struct dp_rx_tid *rx_tid = &peer->rx_tid[tid]; 7608c2ecf20Sopenharmony_ci int ret; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (!rx_tid->active) 7638c2ecf20Sopenharmony_ci return; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS; 7668c2ecf20Sopenharmony_ci cmd.addr_lo = lower_32_bits(rx_tid->paddr); 7678c2ecf20Sopenharmony_ci cmd.addr_hi = upper_32_bits(rx_tid->paddr); 7688c2ecf20Sopenharmony_ci cmd.upd0 |= HAL_REO_CMD_UPD0_VLD; 7698c2ecf20Sopenharmony_ci ret = ath11k_dp_tx_send_reo_cmd(ar->ab, rx_tid, 7708c2ecf20Sopenharmony_ci HAL_REO_CMD_UPDATE_RX_QUEUE, &cmd, 7718c2ecf20Sopenharmony_ci ath11k_dp_rx_tid_del_func); 7728c2ecf20Sopenharmony_ci if (ret) { 7738c2ecf20Sopenharmony_ci ath11k_err(ar->ab, "failed to send HAL_REO_CMD_UPDATE_RX_QUEUE cmd, tid %d (%d)\n", 7748c2ecf20Sopenharmony_ci tid, ret); 7758c2ecf20Sopenharmony_ci dma_unmap_single(ar->ab->dev, rx_tid->paddr, rx_tid->size, 7768c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 7778c2ecf20Sopenharmony_ci kfree(rx_tid->vaddr); 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci rx_tid->active = false; 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_link_desc_return(struct ath11k_base *ab, 7848c2ecf20Sopenharmony_ci u32 *link_desc, 7858c2ecf20Sopenharmony_ci enum hal_wbm_rel_bm_act action) 7868c2ecf20Sopenharmony_ci{ 7878c2ecf20Sopenharmony_ci struct ath11k_dp *dp = &ab->dp; 7888c2ecf20Sopenharmony_ci struct hal_srng *srng; 7898c2ecf20Sopenharmony_ci u32 *desc; 7908c2ecf20Sopenharmony_ci int ret = 0; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci srng = &ab->hal.srng_list[dp->wbm_desc_rel_ring.ring_id]; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci spin_lock_bh(&srng->lock); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci ath11k_hal_srng_access_begin(ab, srng); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci desc = ath11k_hal_srng_src_get_next_entry(ab, srng); 7998c2ecf20Sopenharmony_ci if (!desc) { 8008c2ecf20Sopenharmony_ci ret = -ENOBUFS; 8018c2ecf20Sopenharmony_ci goto exit; 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci ath11k_hal_rx_msdu_link_desc_set(ab, (void *)desc, (void *)link_desc, 8058c2ecf20Sopenharmony_ci action); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ciexit: 8088c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci spin_unlock_bh(&srng->lock); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci return ret; 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_frags_cleanup(struct dp_rx_tid *rx_tid, bool rel_link_desc) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci struct ath11k_base *ab = rx_tid->ab; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci lockdep_assert_held(&ab->base_lock); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci if (rx_tid->dst_ring_desc) { 8228c2ecf20Sopenharmony_ci if (rel_link_desc) 8238c2ecf20Sopenharmony_ci ath11k_dp_rx_link_desc_return(ab, (u32 *)rx_tid->dst_ring_desc, 8248c2ecf20Sopenharmony_ci HAL_WBM_REL_BM_ACT_PUT_IN_IDLE); 8258c2ecf20Sopenharmony_ci kfree(rx_tid->dst_ring_desc); 8268c2ecf20Sopenharmony_ci rx_tid->dst_ring_desc = NULL; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci rx_tid->cur_sn = 0; 8308c2ecf20Sopenharmony_ci rx_tid->last_frag_no = 0; 8318c2ecf20Sopenharmony_ci rx_tid->rx_frag_bitmap = 0; 8328c2ecf20Sopenharmony_ci __skb_queue_purge(&rx_tid->rx_frags); 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_civoid ath11k_peer_frags_flush(struct ath11k *ar, struct ath11k_peer *peer) 8368c2ecf20Sopenharmony_ci{ 8378c2ecf20Sopenharmony_ci struct dp_rx_tid *rx_tid; 8388c2ecf20Sopenharmony_ci int i; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci lockdep_assert_held(&ar->ab->base_lock); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci for (i = 0; i <= IEEE80211_NUM_TIDS; i++) { 8438c2ecf20Sopenharmony_ci rx_tid = &peer->rx_tid[i]; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->ab->base_lock); 8468c2ecf20Sopenharmony_ci del_timer_sync(&rx_tid->frag_timer); 8478c2ecf20Sopenharmony_ci spin_lock_bh(&ar->ab->base_lock); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci ath11k_dp_rx_frags_cleanup(rx_tid, true); 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci} 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_civoid ath11k_peer_rx_tid_cleanup(struct ath11k *ar, struct ath11k_peer *peer) 8548c2ecf20Sopenharmony_ci{ 8558c2ecf20Sopenharmony_ci struct dp_rx_tid *rx_tid; 8568c2ecf20Sopenharmony_ci int i; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci lockdep_assert_held(&ar->ab->base_lock); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci for (i = 0; i <= IEEE80211_NUM_TIDS; i++) { 8618c2ecf20Sopenharmony_ci rx_tid = &peer->rx_tid[i]; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci ath11k_peer_rx_tid_delete(ar, peer, i); 8648c2ecf20Sopenharmony_ci ath11k_dp_rx_frags_cleanup(rx_tid, true); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->ab->base_lock); 8678c2ecf20Sopenharmony_ci del_timer_sync(&rx_tid->frag_timer); 8688c2ecf20Sopenharmony_ci spin_lock_bh(&ar->ab->base_lock); 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_cistatic int ath11k_peer_rx_tid_reo_update(struct ath11k *ar, 8738c2ecf20Sopenharmony_ci struct ath11k_peer *peer, 8748c2ecf20Sopenharmony_ci struct dp_rx_tid *rx_tid, 8758c2ecf20Sopenharmony_ci u32 ba_win_sz, u16 ssn, 8768c2ecf20Sopenharmony_ci bool update_ssn) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci struct ath11k_hal_reo_cmd cmd = {0}; 8798c2ecf20Sopenharmony_ci int ret; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci cmd.addr_lo = lower_32_bits(rx_tid->paddr); 8828c2ecf20Sopenharmony_ci cmd.addr_hi = upper_32_bits(rx_tid->paddr); 8838c2ecf20Sopenharmony_ci cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS; 8848c2ecf20Sopenharmony_ci cmd.upd0 = HAL_REO_CMD_UPD0_BA_WINDOW_SIZE; 8858c2ecf20Sopenharmony_ci cmd.ba_window_size = ba_win_sz; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci if (update_ssn) { 8888c2ecf20Sopenharmony_ci cmd.upd0 |= HAL_REO_CMD_UPD0_SSN; 8898c2ecf20Sopenharmony_ci cmd.upd2 = FIELD_PREP(HAL_REO_CMD_UPD2_SSN, ssn); 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci ret = ath11k_dp_tx_send_reo_cmd(ar->ab, rx_tid, 8938c2ecf20Sopenharmony_ci HAL_REO_CMD_UPDATE_RX_QUEUE, &cmd, 8948c2ecf20Sopenharmony_ci NULL); 8958c2ecf20Sopenharmony_ci if (ret) { 8968c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "failed to update rx tid queue, tid %d (%d)\n", 8978c2ecf20Sopenharmony_ci rx_tid->tid, ret); 8988c2ecf20Sopenharmony_ci return ret; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci rx_tid->ba_win_sz = ba_win_sz; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci return 0; 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_tid_mem_free(struct ath11k_base *ab, 9078c2ecf20Sopenharmony_ci const u8 *peer_mac, int vdev_id, u8 tid) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci struct ath11k_peer *peer; 9108c2ecf20Sopenharmony_ci struct dp_rx_tid *rx_tid; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci spin_lock_bh(&ab->base_lock); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci peer = ath11k_peer_find(ab, vdev_id, peer_mac); 9158c2ecf20Sopenharmony_ci if (!peer) { 9168c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to find the peer to free up rx tid mem\n"); 9178c2ecf20Sopenharmony_ci goto unlock_exit; 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci rx_tid = &peer->rx_tid[tid]; 9218c2ecf20Sopenharmony_ci if (!rx_tid->active) 9228c2ecf20Sopenharmony_ci goto unlock_exit; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size, 9258c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 9268c2ecf20Sopenharmony_ci kfree(rx_tid->vaddr); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci rx_tid->active = false; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ciunlock_exit: 9318c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 9328c2ecf20Sopenharmony_ci} 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ciint ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id, 9358c2ecf20Sopenharmony_ci u8 tid, u32 ba_win_sz, u16 ssn, 9368c2ecf20Sopenharmony_ci enum hal_pn_type pn_type) 9378c2ecf20Sopenharmony_ci{ 9388c2ecf20Sopenharmony_ci struct ath11k_base *ab = ar->ab; 9398c2ecf20Sopenharmony_ci struct ath11k_peer *peer; 9408c2ecf20Sopenharmony_ci struct dp_rx_tid *rx_tid; 9418c2ecf20Sopenharmony_ci u32 hw_desc_sz; 9428c2ecf20Sopenharmony_ci u32 *addr_aligned; 9438c2ecf20Sopenharmony_ci void *vaddr; 9448c2ecf20Sopenharmony_ci dma_addr_t paddr; 9458c2ecf20Sopenharmony_ci int ret; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci spin_lock_bh(&ab->base_lock); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci peer = ath11k_peer_find(ab, vdev_id, peer_mac); 9508c2ecf20Sopenharmony_ci if (!peer) { 9518c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to find the peer to set up rx tid\n"); 9528c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 9538c2ecf20Sopenharmony_ci return -ENOENT; 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci rx_tid = &peer->rx_tid[tid]; 9578c2ecf20Sopenharmony_ci /* Update the tid queue if it is already setup */ 9588c2ecf20Sopenharmony_ci if (rx_tid->active) { 9598c2ecf20Sopenharmony_ci paddr = rx_tid->paddr; 9608c2ecf20Sopenharmony_ci ret = ath11k_peer_rx_tid_reo_update(ar, peer, rx_tid, 9618c2ecf20Sopenharmony_ci ba_win_sz, ssn, true); 9628c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 9638c2ecf20Sopenharmony_ci if (ret) { 9648c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to update reo for rx tid %d\n", tid); 9658c2ecf20Sopenharmony_ci return ret; 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, 9698c2ecf20Sopenharmony_ci peer_mac, paddr, 9708c2ecf20Sopenharmony_ci tid, 1, ba_win_sz); 9718c2ecf20Sopenharmony_ci if (ret) 9728c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to send wmi command to update rx reorder queue, tid :%d (%d)\n", 9738c2ecf20Sopenharmony_ci tid, ret); 9748c2ecf20Sopenharmony_ci return ret; 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci rx_tid->tid = tid; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci rx_tid->ba_win_sz = ba_win_sz; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci /* TODO: Optimize the memory allocation for qos tid based on the 9828c2ecf20Sopenharmony_ci * the actual BA window size in REO tid update path. 9838c2ecf20Sopenharmony_ci */ 9848c2ecf20Sopenharmony_ci if (tid == HAL_DESC_REO_NON_QOS_TID) 9858c2ecf20Sopenharmony_ci hw_desc_sz = ath11k_hal_reo_qdesc_size(ba_win_sz, tid); 9868c2ecf20Sopenharmony_ci else 9878c2ecf20Sopenharmony_ci hw_desc_sz = ath11k_hal_reo_qdesc_size(DP_BA_WIN_SZ_MAX, tid); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci vaddr = kzalloc(hw_desc_sz + HAL_LINK_DESC_ALIGN - 1, GFP_ATOMIC); 9908c2ecf20Sopenharmony_ci if (!vaddr) { 9918c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 9928c2ecf20Sopenharmony_ci return -ENOMEM; 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci addr_aligned = PTR_ALIGN(vaddr, HAL_LINK_DESC_ALIGN); 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci ath11k_hal_reo_qdesc_setup(addr_aligned, tid, ba_win_sz, 9988c2ecf20Sopenharmony_ci ssn, pn_type); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci paddr = dma_map_single(ab->dev, addr_aligned, hw_desc_sz, 10018c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci ret = dma_mapping_error(ab->dev, paddr); 10048c2ecf20Sopenharmony_ci if (ret) { 10058c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 10068c2ecf20Sopenharmony_ci goto err_mem_free; 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci rx_tid->vaddr = vaddr; 10108c2ecf20Sopenharmony_ci rx_tid->paddr = paddr; 10118c2ecf20Sopenharmony_ci rx_tid->size = hw_desc_sz; 10128c2ecf20Sopenharmony_ci rx_tid->active = true; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, peer_mac, 10178c2ecf20Sopenharmony_ci paddr, tid, 1, ba_win_sz); 10188c2ecf20Sopenharmony_ci if (ret) { 10198c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "failed to setup rx reorder queue, tid :%d (%d)\n", 10208c2ecf20Sopenharmony_ci tid, ret); 10218c2ecf20Sopenharmony_ci ath11k_dp_rx_tid_mem_free(ab, peer_mac, vdev_id, tid); 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci return ret; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_cierr_mem_free: 10278c2ecf20Sopenharmony_ci kfree(vaddr); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci return ret; 10308c2ecf20Sopenharmony_ci} 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ciint ath11k_dp_rx_ampdu_start(struct ath11k *ar, 10338c2ecf20Sopenharmony_ci struct ieee80211_ampdu_params *params) 10348c2ecf20Sopenharmony_ci{ 10358c2ecf20Sopenharmony_ci struct ath11k_base *ab = ar->ab; 10368c2ecf20Sopenharmony_ci struct ath11k_sta *arsta = (void *)params->sta->drv_priv; 10378c2ecf20Sopenharmony_ci int vdev_id = arsta->arvif->vdev_id; 10388c2ecf20Sopenharmony_ci int ret; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci ret = ath11k_peer_rx_tid_setup(ar, params->sta->addr, vdev_id, 10418c2ecf20Sopenharmony_ci params->tid, params->buf_size, 10428c2ecf20Sopenharmony_ci params->ssn, arsta->pn_type); 10438c2ecf20Sopenharmony_ci if (ret) 10448c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to setup rx tid %d\n", ret); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci return ret; 10478c2ecf20Sopenharmony_ci} 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ciint ath11k_dp_rx_ampdu_stop(struct ath11k *ar, 10508c2ecf20Sopenharmony_ci struct ieee80211_ampdu_params *params) 10518c2ecf20Sopenharmony_ci{ 10528c2ecf20Sopenharmony_ci struct ath11k_base *ab = ar->ab; 10538c2ecf20Sopenharmony_ci struct ath11k_peer *peer; 10548c2ecf20Sopenharmony_ci struct ath11k_sta *arsta = (void *)params->sta->drv_priv; 10558c2ecf20Sopenharmony_ci int vdev_id = arsta->arvif->vdev_id; 10568c2ecf20Sopenharmony_ci dma_addr_t paddr; 10578c2ecf20Sopenharmony_ci bool active; 10588c2ecf20Sopenharmony_ci int ret; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci spin_lock_bh(&ab->base_lock); 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci peer = ath11k_peer_find(ab, vdev_id, params->sta->addr); 10638c2ecf20Sopenharmony_ci if (!peer) { 10648c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to find the peer to stop rx aggregation\n"); 10658c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 10668c2ecf20Sopenharmony_ci return -ENOENT; 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci paddr = peer->rx_tid[params->tid].paddr; 10708c2ecf20Sopenharmony_ci active = peer->rx_tid[params->tid].active; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci if (!active) { 10738c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 10748c2ecf20Sopenharmony_ci return 0; 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci ret = ath11k_peer_rx_tid_reo_update(ar, peer, peer->rx_tid, 1, 0, false); 10788c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 10798c2ecf20Sopenharmony_ci if (ret) { 10808c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to update reo for rx tid %d: %d\n", 10818c2ecf20Sopenharmony_ci params->tid, ret); 10828c2ecf20Sopenharmony_ci return ret; 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, 10868c2ecf20Sopenharmony_ci params->sta->addr, paddr, 10878c2ecf20Sopenharmony_ci params->tid, 1, 1); 10888c2ecf20Sopenharmony_ci if (ret) 10898c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to send wmi to delete rx tid %d\n", 10908c2ecf20Sopenharmony_ci ret); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci return ret; 10938c2ecf20Sopenharmony_ci} 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ciint ath11k_dp_peer_rx_pn_replay_config(struct ath11k_vif *arvif, 10968c2ecf20Sopenharmony_ci const u8 *peer_addr, 10978c2ecf20Sopenharmony_ci enum set_key_cmd key_cmd, 10988c2ecf20Sopenharmony_ci struct ieee80211_key_conf *key) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci struct ath11k *ar = arvif->ar; 11018c2ecf20Sopenharmony_ci struct ath11k_base *ab = ar->ab; 11028c2ecf20Sopenharmony_ci struct ath11k_hal_reo_cmd cmd = {0}; 11038c2ecf20Sopenharmony_ci struct ath11k_peer *peer; 11048c2ecf20Sopenharmony_ci struct dp_rx_tid *rx_tid; 11058c2ecf20Sopenharmony_ci u8 tid; 11068c2ecf20Sopenharmony_ci int ret = 0; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci /* NOTE: Enable PN/TSC replay check offload only for unicast frames. 11098c2ecf20Sopenharmony_ci * We use mac80211 PN/TSC replay check functionality for bcast/mcast 11108c2ecf20Sopenharmony_ci * for now. 11118c2ecf20Sopenharmony_ci */ 11128c2ecf20Sopenharmony_ci if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 11138c2ecf20Sopenharmony_ci return 0; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci cmd.flag |= HAL_REO_CMD_FLG_NEED_STATUS; 11168c2ecf20Sopenharmony_ci cmd.upd0 |= HAL_REO_CMD_UPD0_PN | 11178c2ecf20Sopenharmony_ci HAL_REO_CMD_UPD0_PN_SIZE | 11188c2ecf20Sopenharmony_ci HAL_REO_CMD_UPD0_PN_VALID | 11198c2ecf20Sopenharmony_ci HAL_REO_CMD_UPD0_PN_CHECK | 11208c2ecf20Sopenharmony_ci HAL_REO_CMD_UPD0_SVLD; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci switch (key->cipher) { 11238c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 11248c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 11258c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP_256: 11268c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP: 11278c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP_256: 11288c2ecf20Sopenharmony_ci if (key_cmd == SET_KEY) { 11298c2ecf20Sopenharmony_ci cmd.upd1 |= HAL_REO_CMD_UPD1_PN_CHECK; 11308c2ecf20Sopenharmony_ci cmd.pn_size = 48; 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci break; 11338c2ecf20Sopenharmony_ci default: 11348c2ecf20Sopenharmony_ci break; 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci spin_lock_bh(&ab->base_lock); 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci peer = ath11k_peer_find(ab, arvif->vdev_id, peer_addr); 11408c2ecf20Sopenharmony_ci if (!peer) { 11418c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to find the peer to configure pn replay detection\n"); 11428c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 11438c2ecf20Sopenharmony_ci return -ENOENT; 11448c2ecf20Sopenharmony_ci } 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci for (tid = 0; tid <= IEEE80211_NUM_TIDS; tid++) { 11478c2ecf20Sopenharmony_ci rx_tid = &peer->rx_tid[tid]; 11488c2ecf20Sopenharmony_ci if (!rx_tid->active) 11498c2ecf20Sopenharmony_ci continue; 11508c2ecf20Sopenharmony_ci cmd.addr_lo = lower_32_bits(rx_tid->paddr); 11518c2ecf20Sopenharmony_ci cmd.addr_hi = upper_32_bits(rx_tid->paddr); 11528c2ecf20Sopenharmony_ci ret = ath11k_dp_tx_send_reo_cmd(ab, rx_tid, 11538c2ecf20Sopenharmony_ci HAL_REO_CMD_UPDATE_RX_QUEUE, 11548c2ecf20Sopenharmony_ci &cmd, NULL); 11558c2ecf20Sopenharmony_ci if (ret) { 11568c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to configure rx tid %d queue for pn replay detection %d\n", 11578c2ecf20Sopenharmony_ci tid, ret); 11588c2ecf20Sopenharmony_ci break; 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->ab->base_lock); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci return ret; 11658c2ecf20Sopenharmony_ci} 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_cistatic inline int ath11k_get_ppdu_user_index(struct htt_ppdu_stats *ppdu_stats, 11688c2ecf20Sopenharmony_ci u16 peer_id) 11698c2ecf20Sopenharmony_ci{ 11708c2ecf20Sopenharmony_ci int i; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci for (i = 0; i < HTT_PPDU_STATS_MAX_USERS - 1; i++) { 11738c2ecf20Sopenharmony_ci if (ppdu_stats->user_stats[i].is_valid_peer_id) { 11748c2ecf20Sopenharmony_ci if (peer_id == ppdu_stats->user_stats[i].peer_id) 11758c2ecf20Sopenharmony_ci return i; 11768c2ecf20Sopenharmony_ci } else { 11778c2ecf20Sopenharmony_ci return i; 11788c2ecf20Sopenharmony_ci } 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci return -EINVAL; 11828c2ecf20Sopenharmony_ci} 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_cistatic int ath11k_htt_tlv_ppdu_stats_parse(struct ath11k_base *ab, 11858c2ecf20Sopenharmony_ci u16 tag, u16 len, const void *ptr, 11868c2ecf20Sopenharmony_ci void *data) 11878c2ecf20Sopenharmony_ci{ 11888c2ecf20Sopenharmony_ci struct htt_ppdu_stats_info *ppdu_info; 11898c2ecf20Sopenharmony_ci struct htt_ppdu_user_stats *user_stats; 11908c2ecf20Sopenharmony_ci int cur_user; 11918c2ecf20Sopenharmony_ci u16 peer_id; 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci ppdu_info = (struct htt_ppdu_stats_info *)data; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci switch (tag) { 11968c2ecf20Sopenharmony_ci case HTT_PPDU_STATS_TAG_COMMON: 11978c2ecf20Sopenharmony_ci if (len < sizeof(struct htt_ppdu_stats_common)) { 11988c2ecf20Sopenharmony_ci ath11k_warn(ab, "Invalid len %d for the tag 0x%x\n", 11998c2ecf20Sopenharmony_ci len, tag); 12008c2ecf20Sopenharmony_ci return -EINVAL; 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci memcpy((void *)&ppdu_info->ppdu_stats.common, ptr, 12038c2ecf20Sopenharmony_ci sizeof(struct htt_ppdu_stats_common)); 12048c2ecf20Sopenharmony_ci break; 12058c2ecf20Sopenharmony_ci case HTT_PPDU_STATS_TAG_USR_RATE: 12068c2ecf20Sopenharmony_ci if (len < sizeof(struct htt_ppdu_stats_user_rate)) { 12078c2ecf20Sopenharmony_ci ath11k_warn(ab, "Invalid len %d for the tag 0x%x\n", 12088c2ecf20Sopenharmony_ci len, tag); 12098c2ecf20Sopenharmony_ci return -EINVAL; 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci peer_id = ((struct htt_ppdu_stats_user_rate *)ptr)->sw_peer_id; 12138c2ecf20Sopenharmony_ci cur_user = ath11k_get_ppdu_user_index(&ppdu_info->ppdu_stats, 12148c2ecf20Sopenharmony_ci peer_id); 12158c2ecf20Sopenharmony_ci if (cur_user < 0) 12168c2ecf20Sopenharmony_ci return -EINVAL; 12178c2ecf20Sopenharmony_ci user_stats = &ppdu_info->ppdu_stats.user_stats[cur_user]; 12188c2ecf20Sopenharmony_ci user_stats->peer_id = peer_id; 12198c2ecf20Sopenharmony_ci user_stats->is_valid_peer_id = true; 12208c2ecf20Sopenharmony_ci memcpy((void *)&user_stats->rate, ptr, 12218c2ecf20Sopenharmony_ci sizeof(struct htt_ppdu_stats_user_rate)); 12228c2ecf20Sopenharmony_ci user_stats->tlv_flags |= BIT(tag); 12238c2ecf20Sopenharmony_ci break; 12248c2ecf20Sopenharmony_ci case HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON: 12258c2ecf20Sopenharmony_ci if (len < sizeof(struct htt_ppdu_stats_usr_cmpltn_cmn)) { 12268c2ecf20Sopenharmony_ci ath11k_warn(ab, "Invalid len %d for the tag 0x%x\n", 12278c2ecf20Sopenharmony_ci len, tag); 12288c2ecf20Sopenharmony_ci return -EINVAL; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci peer_id = ((struct htt_ppdu_stats_usr_cmpltn_cmn *)ptr)->sw_peer_id; 12328c2ecf20Sopenharmony_ci cur_user = ath11k_get_ppdu_user_index(&ppdu_info->ppdu_stats, 12338c2ecf20Sopenharmony_ci peer_id); 12348c2ecf20Sopenharmony_ci if (cur_user < 0) 12358c2ecf20Sopenharmony_ci return -EINVAL; 12368c2ecf20Sopenharmony_ci user_stats = &ppdu_info->ppdu_stats.user_stats[cur_user]; 12378c2ecf20Sopenharmony_ci user_stats->peer_id = peer_id; 12388c2ecf20Sopenharmony_ci user_stats->is_valid_peer_id = true; 12398c2ecf20Sopenharmony_ci memcpy((void *)&user_stats->cmpltn_cmn, ptr, 12408c2ecf20Sopenharmony_ci sizeof(struct htt_ppdu_stats_usr_cmpltn_cmn)); 12418c2ecf20Sopenharmony_ci user_stats->tlv_flags |= BIT(tag); 12428c2ecf20Sopenharmony_ci break; 12438c2ecf20Sopenharmony_ci case HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS: 12448c2ecf20Sopenharmony_ci if (len < 12458c2ecf20Sopenharmony_ci sizeof(struct htt_ppdu_stats_usr_cmpltn_ack_ba_status)) { 12468c2ecf20Sopenharmony_ci ath11k_warn(ab, "Invalid len %d for the tag 0x%x\n", 12478c2ecf20Sopenharmony_ci len, tag); 12488c2ecf20Sopenharmony_ci return -EINVAL; 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci peer_id = 12528c2ecf20Sopenharmony_ci ((struct htt_ppdu_stats_usr_cmpltn_ack_ba_status *)ptr)->sw_peer_id; 12538c2ecf20Sopenharmony_ci cur_user = ath11k_get_ppdu_user_index(&ppdu_info->ppdu_stats, 12548c2ecf20Sopenharmony_ci peer_id); 12558c2ecf20Sopenharmony_ci if (cur_user < 0) 12568c2ecf20Sopenharmony_ci return -EINVAL; 12578c2ecf20Sopenharmony_ci user_stats = &ppdu_info->ppdu_stats.user_stats[cur_user]; 12588c2ecf20Sopenharmony_ci user_stats->peer_id = peer_id; 12598c2ecf20Sopenharmony_ci user_stats->is_valid_peer_id = true; 12608c2ecf20Sopenharmony_ci memcpy((void *)&user_stats->ack_ba, ptr, 12618c2ecf20Sopenharmony_ci sizeof(struct htt_ppdu_stats_usr_cmpltn_ack_ba_status)); 12628c2ecf20Sopenharmony_ci user_stats->tlv_flags |= BIT(tag); 12638c2ecf20Sopenharmony_ci break; 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci return 0; 12668c2ecf20Sopenharmony_ci} 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ciint ath11k_dp_htt_tlv_iter(struct ath11k_base *ab, const void *ptr, size_t len, 12698c2ecf20Sopenharmony_ci int (*iter)(struct ath11k_base *ar, u16 tag, u16 len, 12708c2ecf20Sopenharmony_ci const void *ptr, void *data), 12718c2ecf20Sopenharmony_ci void *data) 12728c2ecf20Sopenharmony_ci{ 12738c2ecf20Sopenharmony_ci const struct htt_tlv *tlv; 12748c2ecf20Sopenharmony_ci const void *begin = ptr; 12758c2ecf20Sopenharmony_ci u16 tlv_tag, tlv_len; 12768c2ecf20Sopenharmony_ci int ret = -EINVAL; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci while (len > 0) { 12798c2ecf20Sopenharmony_ci if (len < sizeof(*tlv)) { 12808c2ecf20Sopenharmony_ci ath11k_err(ab, "htt tlv parse failure at byte %zd (%zu bytes left, %zu expected)\n", 12818c2ecf20Sopenharmony_ci ptr - begin, len, sizeof(*tlv)); 12828c2ecf20Sopenharmony_ci return -EINVAL; 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci tlv = (struct htt_tlv *)ptr; 12858c2ecf20Sopenharmony_ci tlv_tag = FIELD_GET(HTT_TLV_TAG, tlv->header); 12868c2ecf20Sopenharmony_ci tlv_len = FIELD_GET(HTT_TLV_LEN, tlv->header); 12878c2ecf20Sopenharmony_ci ptr += sizeof(*tlv); 12888c2ecf20Sopenharmony_ci len -= sizeof(*tlv); 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci if (tlv_len > len) { 12918c2ecf20Sopenharmony_ci ath11k_err(ab, "htt tlv parse failure of tag %hhu at byte %zd (%zu bytes left, %hhu expected)\n", 12928c2ecf20Sopenharmony_ci tlv_tag, ptr - begin, len, tlv_len); 12938c2ecf20Sopenharmony_ci return -EINVAL; 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci ret = iter(ab, tlv_tag, tlv_len, ptr, data); 12968c2ecf20Sopenharmony_ci if (ret == -ENOMEM) 12978c2ecf20Sopenharmony_ci return ret; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci ptr += tlv_len; 13008c2ecf20Sopenharmony_ci len -= tlv_len; 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci return 0; 13038c2ecf20Sopenharmony_ci} 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_cistatic inline u32 ath11k_he_gi_to_nl80211_he_gi(u8 sgi) 13068c2ecf20Sopenharmony_ci{ 13078c2ecf20Sopenharmony_ci u32 ret = 0; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci switch (sgi) { 13108c2ecf20Sopenharmony_ci case RX_MSDU_START_SGI_0_8_US: 13118c2ecf20Sopenharmony_ci ret = NL80211_RATE_INFO_HE_GI_0_8; 13128c2ecf20Sopenharmony_ci break; 13138c2ecf20Sopenharmony_ci case RX_MSDU_START_SGI_1_6_US: 13148c2ecf20Sopenharmony_ci ret = NL80211_RATE_INFO_HE_GI_1_6; 13158c2ecf20Sopenharmony_ci break; 13168c2ecf20Sopenharmony_ci case RX_MSDU_START_SGI_3_2_US: 13178c2ecf20Sopenharmony_ci ret = NL80211_RATE_INFO_HE_GI_3_2; 13188c2ecf20Sopenharmony_ci break; 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci return ret; 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_cistatic void 13258c2ecf20Sopenharmony_ciath11k_update_per_peer_tx_stats(struct ath11k *ar, 13268c2ecf20Sopenharmony_ci struct htt_ppdu_stats *ppdu_stats, u8 user) 13278c2ecf20Sopenharmony_ci{ 13288c2ecf20Sopenharmony_ci struct ath11k_base *ab = ar->ab; 13298c2ecf20Sopenharmony_ci struct ath11k_peer *peer; 13308c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 13318c2ecf20Sopenharmony_ci struct ath11k_sta *arsta; 13328c2ecf20Sopenharmony_ci struct htt_ppdu_stats_user_rate *user_rate; 13338c2ecf20Sopenharmony_ci struct ath11k_per_peer_tx_stats *peer_stats = &ar->peer_tx_stats; 13348c2ecf20Sopenharmony_ci struct htt_ppdu_user_stats *usr_stats = &ppdu_stats->user_stats[user]; 13358c2ecf20Sopenharmony_ci struct htt_ppdu_stats_common *common = &ppdu_stats->common; 13368c2ecf20Sopenharmony_ci int ret; 13378c2ecf20Sopenharmony_ci u8 flags, mcs, nss, bw, sgi, dcm, rate_idx = 0; 13388c2ecf20Sopenharmony_ci u32 succ_bytes = 0; 13398c2ecf20Sopenharmony_ci u16 rate = 0, succ_pkts = 0; 13408c2ecf20Sopenharmony_ci u32 tx_duration = 0; 13418c2ecf20Sopenharmony_ci u8 tid = HTT_PPDU_STATS_NON_QOS_TID; 13428c2ecf20Sopenharmony_ci bool is_ampdu = false; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci if (!usr_stats) 13458c2ecf20Sopenharmony_ci return; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci if (!(usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_RATE))) 13488c2ecf20Sopenharmony_ci return; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON)) 13518c2ecf20Sopenharmony_ci is_ampdu = 13528c2ecf20Sopenharmony_ci HTT_USR_CMPLTN_IS_AMPDU(usr_stats->cmpltn_cmn.flags); 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci if (usr_stats->tlv_flags & 13558c2ecf20Sopenharmony_ci BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS)) { 13568c2ecf20Sopenharmony_ci succ_bytes = usr_stats->ack_ba.success_bytes; 13578c2ecf20Sopenharmony_ci succ_pkts = FIELD_GET(HTT_PPDU_STATS_ACK_BA_INFO_NUM_MSDU_M, 13588c2ecf20Sopenharmony_ci usr_stats->ack_ba.info); 13598c2ecf20Sopenharmony_ci tid = FIELD_GET(HTT_PPDU_STATS_ACK_BA_INFO_TID_NUM, 13608c2ecf20Sopenharmony_ci usr_stats->ack_ba.info); 13618c2ecf20Sopenharmony_ci } 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci if (common->fes_duration_us) 13648c2ecf20Sopenharmony_ci tx_duration = common->fes_duration_us; 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci user_rate = &usr_stats->rate; 13678c2ecf20Sopenharmony_ci flags = HTT_USR_RATE_PREAMBLE(user_rate->rate_flags); 13688c2ecf20Sopenharmony_ci bw = HTT_USR_RATE_BW(user_rate->rate_flags) - 2; 13698c2ecf20Sopenharmony_ci nss = HTT_USR_RATE_NSS(user_rate->rate_flags) + 1; 13708c2ecf20Sopenharmony_ci mcs = HTT_USR_RATE_MCS(user_rate->rate_flags); 13718c2ecf20Sopenharmony_ci sgi = HTT_USR_RATE_GI(user_rate->rate_flags); 13728c2ecf20Sopenharmony_ci dcm = HTT_USR_RATE_DCM(user_rate->rate_flags); 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci /* Note: If host configured fixed rates and in some other special 13758c2ecf20Sopenharmony_ci * cases, the broadcast/management frames are sent in different rates. 13768c2ecf20Sopenharmony_ci * Firmware rate's control to be skipped for this? 13778c2ecf20Sopenharmony_ci */ 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (flags == WMI_RATE_PREAMBLE_HE && mcs > 11) { 13808c2ecf20Sopenharmony_ci ath11k_warn(ab, "Invalid HE mcs %hhd peer stats", mcs); 13818c2ecf20Sopenharmony_ci return; 13828c2ecf20Sopenharmony_ci } 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci if (flags == WMI_RATE_PREAMBLE_HE && mcs > ATH11K_HE_MCS_MAX) { 13858c2ecf20Sopenharmony_ci ath11k_warn(ab, "Invalid HE mcs %hhd peer stats", mcs); 13868c2ecf20Sopenharmony_ci return; 13878c2ecf20Sopenharmony_ci } 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci if (flags == WMI_RATE_PREAMBLE_VHT && mcs > ATH11K_VHT_MCS_MAX) { 13908c2ecf20Sopenharmony_ci ath11k_warn(ab, "Invalid VHT mcs %hhd peer stats", mcs); 13918c2ecf20Sopenharmony_ci return; 13928c2ecf20Sopenharmony_ci } 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci if (flags == WMI_RATE_PREAMBLE_HT && (mcs > ATH11K_HT_MCS_MAX || nss < 1)) { 13958c2ecf20Sopenharmony_ci ath11k_warn(ab, "Invalid HT mcs %hhd nss %hhd peer stats", 13968c2ecf20Sopenharmony_ci mcs, nss); 13978c2ecf20Sopenharmony_ci return; 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if (flags == WMI_RATE_PREAMBLE_CCK || flags == WMI_RATE_PREAMBLE_OFDM) { 14018c2ecf20Sopenharmony_ci ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs, 14028c2ecf20Sopenharmony_ci flags, 14038c2ecf20Sopenharmony_ci &rate_idx, 14048c2ecf20Sopenharmony_ci &rate); 14058c2ecf20Sopenharmony_ci if (ret < 0) 14068c2ecf20Sopenharmony_ci return; 14078c2ecf20Sopenharmony_ci } 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci rcu_read_lock(); 14108c2ecf20Sopenharmony_ci spin_lock_bh(&ab->base_lock); 14118c2ecf20Sopenharmony_ci peer = ath11k_peer_find_by_id(ab, usr_stats->peer_id); 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci if (!peer || !peer->sta) { 14148c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 14158c2ecf20Sopenharmony_ci rcu_read_unlock(); 14168c2ecf20Sopenharmony_ci return; 14178c2ecf20Sopenharmony_ci } 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci sta = peer->sta; 14208c2ecf20Sopenharmony_ci arsta = (struct ath11k_sta *)sta->drv_priv; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci memset(&arsta->txrate, 0, sizeof(arsta->txrate)); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci switch (flags) { 14258c2ecf20Sopenharmony_ci case WMI_RATE_PREAMBLE_OFDM: 14268c2ecf20Sopenharmony_ci arsta->txrate.legacy = rate; 14278c2ecf20Sopenharmony_ci break; 14288c2ecf20Sopenharmony_ci case WMI_RATE_PREAMBLE_CCK: 14298c2ecf20Sopenharmony_ci arsta->txrate.legacy = rate; 14308c2ecf20Sopenharmony_ci break; 14318c2ecf20Sopenharmony_ci case WMI_RATE_PREAMBLE_HT: 14328c2ecf20Sopenharmony_ci arsta->txrate.mcs = mcs + 8 * (nss - 1); 14338c2ecf20Sopenharmony_ci arsta->txrate.flags = RATE_INFO_FLAGS_MCS; 14348c2ecf20Sopenharmony_ci if (sgi) 14358c2ecf20Sopenharmony_ci arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; 14368c2ecf20Sopenharmony_ci break; 14378c2ecf20Sopenharmony_ci case WMI_RATE_PREAMBLE_VHT: 14388c2ecf20Sopenharmony_ci arsta->txrate.mcs = mcs; 14398c2ecf20Sopenharmony_ci arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS; 14408c2ecf20Sopenharmony_ci if (sgi) 14418c2ecf20Sopenharmony_ci arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; 14428c2ecf20Sopenharmony_ci break; 14438c2ecf20Sopenharmony_ci case WMI_RATE_PREAMBLE_HE: 14448c2ecf20Sopenharmony_ci arsta->txrate.mcs = mcs; 14458c2ecf20Sopenharmony_ci arsta->txrate.flags = RATE_INFO_FLAGS_HE_MCS; 14468c2ecf20Sopenharmony_ci arsta->txrate.he_dcm = dcm; 14478c2ecf20Sopenharmony_ci arsta->txrate.he_gi = ath11k_he_gi_to_nl80211_he_gi(sgi); 14488c2ecf20Sopenharmony_ci arsta->txrate.he_ru_alloc = ath11k_he_ru_tones_to_nl80211_he_ru_alloc( 14498c2ecf20Sopenharmony_ci (user_rate->ru_end - 14508c2ecf20Sopenharmony_ci user_rate->ru_start) + 1); 14518c2ecf20Sopenharmony_ci break; 14528c2ecf20Sopenharmony_ci } 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci arsta->txrate.nss = nss; 14558c2ecf20Sopenharmony_ci arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw); 14568c2ecf20Sopenharmony_ci arsta->tx_duration += tx_duration; 14578c2ecf20Sopenharmony_ci memcpy(&arsta->last_txrate, &arsta->txrate, sizeof(struct rate_info)); 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci /* PPDU stats reported for mgmt packet doesn't have valid tx bytes. 14608c2ecf20Sopenharmony_ci * So skip peer stats update for mgmt packets. 14618c2ecf20Sopenharmony_ci */ 14628c2ecf20Sopenharmony_ci if (tid < HTT_PPDU_STATS_NON_QOS_TID) { 14638c2ecf20Sopenharmony_ci memset(peer_stats, 0, sizeof(*peer_stats)); 14648c2ecf20Sopenharmony_ci peer_stats->succ_pkts = succ_pkts; 14658c2ecf20Sopenharmony_ci peer_stats->succ_bytes = succ_bytes; 14668c2ecf20Sopenharmony_ci peer_stats->is_ampdu = is_ampdu; 14678c2ecf20Sopenharmony_ci peer_stats->duration = tx_duration; 14688c2ecf20Sopenharmony_ci peer_stats->ba_fails = 14698c2ecf20Sopenharmony_ci HTT_USR_CMPLTN_LONG_RETRY(usr_stats->cmpltn_cmn.flags) + 14708c2ecf20Sopenharmony_ci HTT_USR_CMPLTN_SHORT_RETRY(usr_stats->cmpltn_cmn.flags); 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) 14738c2ecf20Sopenharmony_ci ath11k_debugfs_sta_add_tx_stats(arsta, peer_stats, rate_idx); 14748c2ecf20Sopenharmony_ci } 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 14778c2ecf20Sopenharmony_ci rcu_read_unlock(); 14788c2ecf20Sopenharmony_ci} 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_cistatic void ath11k_htt_update_ppdu_stats(struct ath11k *ar, 14818c2ecf20Sopenharmony_ci struct htt_ppdu_stats *ppdu_stats) 14828c2ecf20Sopenharmony_ci{ 14838c2ecf20Sopenharmony_ci u8 user; 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci for (user = 0; user < HTT_PPDU_STATS_MAX_USERS - 1; user++) 14868c2ecf20Sopenharmony_ci ath11k_update_per_peer_tx_stats(ar, ppdu_stats, user); 14878c2ecf20Sopenharmony_ci} 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_cistatic 14908c2ecf20Sopenharmony_cistruct htt_ppdu_stats_info *ath11k_dp_htt_get_ppdu_desc(struct ath11k *ar, 14918c2ecf20Sopenharmony_ci u32 ppdu_id) 14928c2ecf20Sopenharmony_ci{ 14938c2ecf20Sopenharmony_ci struct htt_ppdu_stats_info *ppdu_info; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 14968c2ecf20Sopenharmony_ci if (!list_empty(&ar->ppdu_stats_info)) { 14978c2ecf20Sopenharmony_ci list_for_each_entry(ppdu_info, &ar->ppdu_stats_info, list) { 14988c2ecf20Sopenharmony_ci if (ppdu_info->ppdu_id == ppdu_id) { 14998c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 15008c2ecf20Sopenharmony_ci return ppdu_info; 15018c2ecf20Sopenharmony_ci } 15028c2ecf20Sopenharmony_ci } 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci if (ar->ppdu_stat_list_depth > HTT_PPDU_DESC_MAX_DEPTH) { 15058c2ecf20Sopenharmony_ci ppdu_info = list_first_entry(&ar->ppdu_stats_info, 15068c2ecf20Sopenharmony_ci typeof(*ppdu_info), list); 15078c2ecf20Sopenharmony_ci list_del(&ppdu_info->list); 15088c2ecf20Sopenharmony_ci ar->ppdu_stat_list_depth--; 15098c2ecf20Sopenharmony_ci ath11k_htt_update_ppdu_stats(ar, &ppdu_info->ppdu_stats); 15108c2ecf20Sopenharmony_ci kfree(ppdu_info); 15118c2ecf20Sopenharmony_ci } 15128c2ecf20Sopenharmony_ci } 15138c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci ppdu_info = kzalloc(sizeof(*ppdu_info), GFP_ATOMIC); 15168c2ecf20Sopenharmony_ci if (!ppdu_info) 15178c2ecf20Sopenharmony_ci return NULL; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 15208c2ecf20Sopenharmony_ci list_add_tail(&ppdu_info->list, &ar->ppdu_stats_info); 15218c2ecf20Sopenharmony_ci ar->ppdu_stat_list_depth++; 15228c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci return ppdu_info; 15258c2ecf20Sopenharmony_ci} 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_cistatic int ath11k_htt_pull_ppdu_stats(struct ath11k_base *ab, 15288c2ecf20Sopenharmony_ci struct sk_buff *skb) 15298c2ecf20Sopenharmony_ci{ 15308c2ecf20Sopenharmony_ci struct ath11k_htt_ppdu_stats_msg *msg; 15318c2ecf20Sopenharmony_ci struct htt_ppdu_stats_info *ppdu_info; 15328c2ecf20Sopenharmony_ci struct ath11k *ar; 15338c2ecf20Sopenharmony_ci int ret; 15348c2ecf20Sopenharmony_ci u8 pdev_id; 15358c2ecf20Sopenharmony_ci u32 ppdu_id, len; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci msg = (struct ath11k_htt_ppdu_stats_msg *)skb->data; 15388c2ecf20Sopenharmony_ci len = FIELD_GET(HTT_T2H_PPDU_STATS_INFO_PAYLOAD_SIZE, msg->info); 15398c2ecf20Sopenharmony_ci pdev_id = FIELD_GET(HTT_T2H_PPDU_STATS_INFO_PDEV_ID, msg->info); 15408c2ecf20Sopenharmony_ci ppdu_id = msg->ppdu_id; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci rcu_read_lock(); 15438c2ecf20Sopenharmony_ci ar = ath11k_mac_get_ar_by_pdev_id(ab, pdev_id); 15448c2ecf20Sopenharmony_ci if (!ar) { 15458c2ecf20Sopenharmony_ci ret = -EINVAL; 15468c2ecf20Sopenharmony_ci goto exit; 15478c2ecf20Sopenharmony_ci } 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar)) 15508c2ecf20Sopenharmony_ci trace_ath11k_htt_ppdu_stats(ar, skb->data, len); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci ppdu_info = ath11k_dp_htt_get_ppdu_desc(ar, ppdu_id); 15538c2ecf20Sopenharmony_ci if (!ppdu_info) { 15548c2ecf20Sopenharmony_ci ret = -EINVAL; 15558c2ecf20Sopenharmony_ci goto exit; 15568c2ecf20Sopenharmony_ci } 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci ppdu_info->ppdu_id = ppdu_id; 15598c2ecf20Sopenharmony_ci ret = ath11k_dp_htt_tlv_iter(ab, msg->data, len, 15608c2ecf20Sopenharmony_ci ath11k_htt_tlv_ppdu_stats_parse, 15618c2ecf20Sopenharmony_ci (void *)ppdu_info); 15628c2ecf20Sopenharmony_ci if (ret) { 15638c2ecf20Sopenharmony_ci ath11k_warn(ab, "Failed to parse tlv %d\n", ret); 15648c2ecf20Sopenharmony_ci goto exit; 15658c2ecf20Sopenharmony_ci } 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ciexit: 15688c2ecf20Sopenharmony_ci rcu_read_unlock(); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci return ret; 15718c2ecf20Sopenharmony_ci} 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_cistatic void ath11k_htt_pktlog(struct ath11k_base *ab, struct sk_buff *skb) 15748c2ecf20Sopenharmony_ci{ 15758c2ecf20Sopenharmony_ci struct htt_pktlog_msg *data = (struct htt_pktlog_msg *)skb->data; 15768c2ecf20Sopenharmony_ci struct ath_pktlog_hdr *hdr = (struct ath_pktlog_hdr *)data; 15778c2ecf20Sopenharmony_ci struct ath11k *ar; 15788c2ecf20Sopenharmony_ci u8 pdev_id; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci pdev_id = FIELD_GET(HTT_T2H_PPDU_STATS_INFO_PDEV_ID, data->hdr); 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci rcu_read_lock(); 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci ar = ath11k_mac_get_ar_by_pdev_id(ab, pdev_id); 15858c2ecf20Sopenharmony_ci if (!ar) { 15868c2ecf20Sopenharmony_ci ath11k_warn(ab, "invalid pdev id %d on htt pktlog\n", pdev_id); 15878c2ecf20Sopenharmony_ci goto out; 15888c2ecf20Sopenharmony_ci } 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci trace_ath11k_htt_pktlog(ar, data->payload, hdr->size, 15918c2ecf20Sopenharmony_ci ar->ab->pktlog_defs_checksum); 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ciout: 15948c2ecf20Sopenharmony_ci rcu_read_unlock(); 15958c2ecf20Sopenharmony_ci} 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_cistatic void ath11k_htt_backpressure_event_handler(struct ath11k_base *ab, 15988c2ecf20Sopenharmony_ci struct sk_buff *skb) 15998c2ecf20Sopenharmony_ci{ 16008c2ecf20Sopenharmony_ci u32 *data = (u32 *)skb->data; 16018c2ecf20Sopenharmony_ci u8 pdev_id, ring_type, ring_id, pdev_idx; 16028c2ecf20Sopenharmony_ci u16 hp, tp; 16038c2ecf20Sopenharmony_ci u32 backpressure_time; 16048c2ecf20Sopenharmony_ci struct ath11k_bp_stats *bp_stats; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci pdev_id = FIELD_GET(HTT_BACKPRESSURE_EVENT_PDEV_ID_M, *data); 16078c2ecf20Sopenharmony_ci ring_type = FIELD_GET(HTT_BACKPRESSURE_EVENT_RING_TYPE_M, *data); 16088c2ecf20Sopenharmony_ci ring_id = FIELD_GET(HTT_BACKPRESSURE_EVENT_RING_ID_M, *data); 16098c2ecf20Sopenharmony_ci ++data; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci hp = FIELD_GET(HTT_BACKPRESSURE_EVENT_HP_M, *data); 16128c2ecf20Sopenharmony_ci tp = FIELD_GET(HTT_BACKPRESSURE_EVENT_TP_M, *data); 16138c2ecf20Sopenharmony_ci ++data; 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci backpressure_time = *data; 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "htt backpressure event, pdev %d, ring type %d,ring id %d, hp %d tp %d, backpressure time %d\n", 16188c2ecf20Sopenharmony_ci pdev_id, ring_type, ring_id, hp, tp, backpressure_time); 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci if (ring_type == HTT_BACKPRESSURE_UMAC_RING_TYPE) { 16218c2ecf20Sopenharmony_ci if (ring_id >= HTT_SW_UMAC_RING_IDX_MAX) 16228c2ecf20Sopenharmony_ci return; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci bp_stats = &ab->soc_stats.bp_stats.umac_ring_bp_stats[ring_id]; 16258c2ecf20Sopenharmony_ci } else if (ring_type == HTT_BACKPRESSURE_LMAC_RING_TYPE) { 16268c2ecf20Sopenharmony_ci pdev_idx = DP_HW2SW_MACID(pdev_id); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci if (ring_id >= HTT_SW_LMAC_RING_IDX_MAX || pdev_idx >= MAX_RADIOS) 16298c2ecf20Sopenharmony_ci return; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci bp_stats = &ab->soc_stats.bp_stats.lmac_ring_bp_stats[ring_id][pdev_idx]; 16328c2ecf20Sopenharmony_ci } else { 16338c2ecf20Sopenharmony_ci ath11k_warn(ab, "unknown ring type received in htt bp event %d\n", 16348c2ecf20Sopenharmony_ci ring_type); 16358c2ecf20Sopenharmony_ci return; 16368c2ecf20Sopenharmony_ci } 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci spin_lock_bh(&ab->base_lock); 16398c2ecf20Sopenharmony_ci bp_stats->hp = hp; 16408c2ecf20Sopenharmony_ci bp_stats->tp = tp; 16418c2ecf20Sopenharmony_ci bp_stats->count++; 16428c2ecf20Sopenharmony_ci bp_stats->jiffies = jiffies; 16438c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 16448c2ecf20Sopenharmony_ci} 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_civoid ath11k_dp_htt_htc_t2h_msg_handler(struct ath11k_base *ab, 16478c2ecf20Sopenharmony_ci struct sk_buff *skb) 16488c2ecf20Sopenharmony_ci{ 16498c2ecf20Sopenharmony_ci struct ath11k_dp *dp = &ab->dp; 16508c2ecf20Sopenharmony_ci struct htt_resp_msg *resp = (struct htt_resp_msg *)skb->data; 16518c2ecf20Sopenharmony_ci enum htt_t2h_msg_type type = FIELD_GET(HTT_T2H_MSG_TYPE, *(u32 *)resp); 16528c2ecf20Sopenharmony_ci u16 peer_id; 16538c2ecf20Sopenharmony_ci u8 vdev_id; 16548c2ecf20Sopenharmony_ci u8 mac_addr[ETH_ALEN]; 16558c2ecf20Sopenharmony_ci u16 peer_mac_h16; 16568c2ecf20Sopenharmony_ci u16 ast_hash; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "dp_htt rx msg type :0x%0x\n", type); 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci switch (type) { 16618c2ecf20Sopenharmony_ci case HTT_T2H_MSG_TYPE_VERSION_CONF: 16628c2ecf20Sopenharmony_ci dp->htt_tgt_ver_major = FIELD_GET(HTT_T2H_VERSION_CONF_MAJOR, 16638c2ecf20Sopenharmony_ci resp->version_msg.version); 16648c2ecf20Sopenharmony_ci dp->htt_tgt_ver_minor = FIELD_GET(HTT_T2H_VERSION_CONF_MINOR, 16658c2ecf20Sopenharmony_ci resp->version_msg.version); 16668c2ecf20Sopenharmony_ci complete(&dp->htt_tgt_version_received); 16678c2ecf20Sopenharmony_ci break; 16688c2ecf20Sopenharmony_ci case HTT_T2H_MSG_TYPE_PEER_MAP: 16698c2ecf20Sopenharmony_ci vdev_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_VDEV_ID, 16708c2ecf20Sopenharmony_ci resp->peer_map_ev.info); 16718c2ecf20Sopenharmony_ci peer_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_PEER_ID, 16728c2ecf20Sopenharmony_ci resp->peer_map_ev.info); 16738c2ecf20Sopenharmony_ci peer_mac_h16 = FIELD_GET(HTT_T2H_PEER_MAP_INFO1_MAC_ADDR_H16, 16748c2ecf20Sopenharmony_ci resp->peer_map_ev.info1); 16758c2ecf20Sopenharmony_ci ath11k_dp_get_mac_addr(resp->peer_map_ev.mac_addr_l32, 16768c2ecf20Sopenharmony_ci peer_mac_h16, mac_addr); 16778c2ecf20Sopenharmony_ci ath11k_peer_map_event(ab, vdev_id, peer_id, mac_addr, 0); 16788c2ecf20Sopenharmony_ci break; 16798c2ecf20Sopenharmony_ci case HTT_T2H_MSG_TYPE_PEER_MAP2: 16808c2ecf20Sopenharmony_ci vdev_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_VDEV_ID, 16818c2ecf20Sopenharmony_ci resp->peer_map_ev.info); 16828c2ecf20Sopenharmony_ci peer_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_PEER_ID, 16838c2ecf20Sopenharmony_ci resp->peer_map_ev.info); 16848c2ecf20Sopenharmony_ci peer_mac_h16 = FIELD_GET(HTT_T2H_PEER_MAP_INFO1_MAC_ADDR_H16, 16858c2ecf20Sopenharmony_ci resp->peer_map_ev.info1); 16868c2ecf20Sopenharmony_ci ath11k_dp_get_mac_addr(resp->peer_map_ev.mac_addr_l32, 16878c2ecf20Sopenharmony_ci peer_mac_h16, mac_addr); 16888c2ecf20Sopenharmony_ci ast_hash = FIELD_GET(HTT_T2H_PEER_MAP_INFO2_AST_HASH_VAL, 16898c2ecf20Sopenharmony_ci resp->peer_map_ev.info2); 16908c2ecf20Sopenharmony_ci ath11k_peer_map_event(ab, vdev_id, peer_id, mac_addr, ast_hash); 16918c2ecf20Sopenharmony_ci break; 16928c2ecf20Sopenharmony_ci case HTT_T2H_MSG_TYPE_PEER_UNMAP: 16938c2ecf20Sopenharmony_ci case HTT_T2H_MSG_TYPE_PEER_UNMAP2: 16948c2ecf20Sopenharmony_ci peer_id = FIELD_GET(HTT_T2H_PEER_UNMAP_INFO_PEER_ID, 16958c2ecf20Sopenharmony_ci resp->peer_unmap_ev.info); 16968c2ecf20Sopenharmony_ci ath11k_peer_unmap_event(ab, peer_id); 16978c2ecf20Sopenharmony_ci break; 16988c2ecf20Sopenharmony_ci case HTT_T2H_MSG_TYPE_PPDU_STATS_IND: 16998c2ecf20Sopenharmony_ci ath11k_htt_pull_ppdu_stats(ab, skb); 17008c2ecf20Sopenharmony_ci break; 17018c2ecf20Sopenharmony_ci case HTT_T2H_MSG_TYPE_EXT_STATS_CONF: 17028c2ecf20Sopenharmony_ci ath11k_debugfs_htt_ext_stats_handler(ab, skb); 17038c2ecf20Sopenharmony_ci break; 17048c2ecf20Sopenharmony_ci case HTT_T2H_MSG_TYPE_PKTLOG: 17058c2ecf20Sopenharmony_ci ath11k_htt_pktlog(ab, skb); 17068c2ecf20Sopenharmony_ci break; 17078c2ecf20Sopenharmony_ci case HTT_T2H_MSG_TYPE_BKPRESSURE_EVENT_IND: 17088c2ecf20Sopenharmony_ci ath11k_htt_backpressure_event_handler(ab, skb); 17098c2ecf20Sopenharmony_ci break; 17108c2ecf20Sopenharmony_ci default: 17118c2ecf20Sopenharmony_ci ath11k_warn(ab, "htt event %d not handled\n", type); 17128c2ecf20Sopenharmony_ci break; 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 17168c2ecf20Sopenharmony_ci} 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_msdu_coalesce(struct ath11k *ar, 17198c2ecf20Sopenharmony_ci struct sk_buff_head *msdu_list, 17208c2ecf20Sopenharmony_ci struct sk_buff *first, struct sk_buff *last, 17218c2ecf20Sopenharmony_ci u8 l3pad_bytes, int msdu_len) 17228c2ecf20Sopenharmony_ci{ 17238c2ecf20Sopenharmony_ci struct sk_buff *skb; 17248c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(first); 17258c2ecf20Sopenharmony_ci int buf_first_hdr_len, buf_first_len; 17268c2ecf20Sopenharmony_ci struct hal_rx_desc *ldesc; 17278c2ecf20Sopenharmony_ci int space_extra; 17288c2ecf20Sopenharmony_ci int rem_len; 17298c2ecf20Sopenharmony_ci int buf_len; 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci /* As the msdu is spread across multiple rx buffers, 17328c2ecf20Sopenharmony_ci * find the offset to the start of msdu for computing 17338c2ecf20Sopenharmony_ci * the length of the msdu in the first buffer. 17348c2ecf20Sopenharmony_ci */ 17358c2ecf20Sopenharmony_ci buf_first_hdr_len = HAL_RX_DESC_SIZE + l3pad_bytes; 17368c2ecf20Sopenharmony_ci buf_first_len = DP_RX_BUFFER_SIZE - buf_first_hdr_len; 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(msdu_len <= buf_first_len)) { 17398c2ecf20Sopenharmony_ci skb_put(first, buf_first_hdr_len + msdu_len); 17408c2ecf20Sopenharmony_ci skb_pull(first, buf_first_hdr_len); 17418c2ecf20Sopenharmony_ci return 0; 17428c2ecf20Sopenharmony_ci } 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci ldesc = (struct hal_rx_desc *)last->data; 17458c2ecf20Sopenharmony_ci rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(ldesc); 17468c2ecf20Sopenharmony_ci rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(ldesc); 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci /* MSDU spans over multiple buffers because the length of the MSDU 17498c2ecf20Sopenharmony_ci * exceeds DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE. So assume the data 17508c2ecf20Sopenharmony_ci * in the first buf is of length DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE. 17518c2ecf20Sopenharmony_ci */ 17528c2ecf20Sopenharmony_ci skb_put(first, DP_RX_BUFFER_SIZE); 17538c2ecf20Sopenharmony_ci skb_pull(first, buf_first_hdr_len); 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci /* When an MSDU spread over multiple buffers attention, MSDU_END and 17568c2ecf20Sopenharmony_ci * MPDU_END tlvs are valid only in the last buffer. Copy those tlvs. 17578c2ecf20Sopenharmony_ci */ 17588c2ecf20Sopenharmony_ci ath11k_dp_rx_desc_end_tlv_copy(rxcb->rx_desc, ldesc); 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci space_extra = msdu_len - (buf_first_len + skb_tailroom(first)); 17618c2ecf20Sopenharmony_ci if (space_extra > 0 && 17628c2ecf20Sopenharmony_ci (pskb_expand_head(first, 0, space_extra, GFP_ATOMIC) < 0)) { 17638c2ecf20Sopenharmony_ci /* Free up all buffers of the MSDU */ 17648c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(msdu_list)) != NULL) { 17658c2ecf20Sopenharmony_ci rxcb = ATH11K_SKB_RXCB(skb); 17668c2ecf20Sopenharmony_ci if (!rxcb->is_continuation) { 17678c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 17688c2ecf20Sopenharmony_ci break; 17698c2ecf20Sopenharmony_ci } 17708c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 17718c2ecf20Sopenharmony_ci } 17728c2ecf20Sopenharmony_ci return -ENOMEM; 17738c2ecf20Sopenharmony_ci } 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci rem_len = msdu_len - buf_first_len; 17768c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(msdu_list)) != NULL && rem_len > 0) { 17778c2ecf20Sopenharmony_ci rxcb = ATH11K_SKB_RXCB(skb); 17788c2ecf20Sopenharmony_ci if (rxcb->is_continuation) 17798c2ecf20Sopenharmony_ci buf_len = DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE; 17808c2ecf20Sopenharmony_ci else 17818c2ecf20Sopenharmony_ci buf_len = rem_len; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci if (buf_len > (DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE)) { 17848c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 17858c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 17868c2ecf20Sopenharmony_ci return -EINVAL; 17878c2ecf20Sopenharmony_ci } 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci skb_put(skb, buf_len + HAL_RX_DESC_SIZE); 17908c2ecf20Sopenharmony_ci skb_pull(skb, HAL_RX_DESC_SIZE); 17918c2ecf20Sopenharmony_ci skb_copy_from_linear_data(skb, skb_put(first, buf_len), 17928c2ecf20Sopenharmony_ci buf_len); 17938c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci rem_len -= buf_len; 17968c2ecf20Sopenharmony_ci if (!rxcb->is_continuation) 17978c2ecf20Sopenharmony_ci break; 17988c2ecf20Sopenharmony_ci } 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci return 0; 18018c2ecf20Sopenharmony_ci} 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_cistatic struct sk_buff *ath11k_dp_rx_get_msdu_last_buf(struct sk_buff_head *msdu_list, 18048c2ecf20Sopenharmony_ci struct sk_buff *first) 18058c2ecf20Sopenharmony_ci{ 18068c2ecf20Sopenharmony_ci struct sk_buff *skb; 18078c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(first); 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci if (!rxcb->is_continuation) 18108c2ecf20Sopenharmony_ci return first; 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci skb_queue_walk(msdu_list, skb) { 18138c2ecf20Sopenharmony_ci rxcb = ATH11K_SKB_RXCB(skb); 18148c2ecf20Sopenharmony_ci if (!rxcb->is_continuation) 18158c2ecf20Sopenharmony_ci return skb; 18168c2ecf20Sopenharmony_ci } 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci return NULL; 18198c2ecf20Sopenharmony_ci} 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_csum_offload(struct sk_buff *msdu) 18228c2ecf20Sopenharmony_ci{ 18238c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 18248c2ecf20Sopenharmony_ci bool ip_csum_fail, l4_csum_fail; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci ip_csum_fail = ath11k_dp_rx_h_attn_ip_cksum_fail(rxcb->rx_desc); 18278c2ecf20Sopenharmony_ci l4_csum_fail = ath11k_dp_rx_h_attn_l4_cksum_fail(rxcb->rx_desc); 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci msdu->ip_summed = (ip_csum_fail || l4_csum_fail) ? 18308c2ecf20Sopenharmony_ci CHECKSUM_NONE : CHECKSUM_UNNECESSARY; 18318c2ecf20Sopenharmony_ci} 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_crypto_mic_len(struct ath11k *ar, 18348c2ecf20Sopenharmony_ci enum hal_encrypt_type enctype) 18358c2ecf20Sopenharmony_ci{ 18368c2ecf20Sopenharmony_ci switch (enctype) { 18378c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_OPEN: 18388c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_TKIP_NO_MIC: 18398c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_TKIP_MIC: 18408c2ecf20Sopenharmony_ci return 0; 18418c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_CCMP_128: 18428c2ecf20Sopenharmony_ci return IEEE80211_CCMP_MIC_LEN; 18438c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_CCMP_256: 18448c2ecf20Sopenharmony_ci return IEEE80211_CCMP_256_MIC_LEN; 18458c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_GCMP_128: 18468c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_AES_GCMP_256: 18478c2ecf20Sopenharmony_ci return IEEE80211_GCMP_MIC_LEN; 18488c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_WEP_40: 18498c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_WEP_104: 18508c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_WEP_128: 18518c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4: 18528c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_WAPI: 18538c2ecf20Sopenharmony_ci break; 18548c2ecf20Sopenharmony_ci } 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "unsupported encryption type %d for mic len\n", enctype); 18578c2ecf20Sopenharmony_ci return 0; 18588c2ecf20Sopenharmony_ci} 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_crypto_param_len(struct ath11k *ar, 18618c2ecf20Sopenharmony_ci enum hal_encrypt_type enctype) 18628c2ecf20Sopenharmony_ci{ 18638c2ecf20Sopenharmony_ci switch (enctype) { 18648c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_OPEN: 18658c2ecf20Sopenharmony_ci return 0; 18668c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_TKIP_NO_MIC: 18678c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_TKIP_MIC: 18688c2ecf20Sopenharmony_ci return IEEE80211_TKIP_IV_LEN; 18698c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_CCMP_128: 18708c2ecf20Sopenharmony_ci return IEEE80211_CCMP_HDR_LEN; 18718c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_CCMP_256: 18728c2ecf20Sopenharmony_ci return IEEE80211_CCMP_256_HDR_LEN; 18738c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_GCMP_128: 18748c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_AES_GCMP_256: 18758c2ecf20Sopenharmony_ci return IEEE80211_GCMP_HDR_LEN; 18768c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_WEP_40: 18778c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_WEP_104: 18788c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_WEP_128: 18798c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4: 18808c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_WAPI: 18818c2ecf20Sopenharmony_ci break; 18828c2ecf20Sopenharmony_ci } 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "unsupported encryption type %d\n", enctype); 18858c2ecf20Sopenharmony_ci return 0; 18868c2ecf20Sopenharmony_ci} 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_crypto_icv_len(struct ath11k *ar, 18898c2ecf20Sopenharmony_ci enum hal_encrypt_type enctype) 18908c2ecf20Sopenharmony_ci{ 18918c2ecf20Sopenharmony_ci switch (enctype) { 18928c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_OPEN: 18938c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_CCMP_128: 18948c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_CCMP_256: 18958c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_GCMP_128: 18968c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_AES_GCMP_256: 18978c2ecf20Sopenharmony_ci return 0; 18988c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_TKIP_NO_MIC: 18998c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_TKIP_MIC: 19008c2ecf20Sopenharmony_ci return IEEE80211_TKIP_ICV_LEN; 19018c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_WEP_40: 19028c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_WEP_104: 19038c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_WEP_128: 19048c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4: 19058c2ecf20Sopenharmony_ci case HAL_ENCRYPT_TYPE_WAPI: 19068c2ecf20Sopenharmony_ci break; 19078c2ecf20Sopenharmony_ci } 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "unsupported encryption type %d\n", enctype); 19108c2ecf20Sopenharmony_ci return 0; 19118c2ecf20Sopenharmony_ci} 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_undecap_nwifi(struct ath11k *ar, 19148c2ecf20Sopenharmony_ci struct sk_buff *msdu, 19158c2ecf20Sopenharmony_ci u8 *first_hdr, 19168c2ecf20Sopenharmony_ci enum hal_encrypt_type enctype, 19178c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status) 19188c2ecf20Sopenharmony_ci{ 19198c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 19208c2ecf20Sopenharmony_ci u8 decap_hdr[DP_MAX_NWIFI_HDR_LEN]; 19218c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 19228c2ecf20Sopenharmony_ci size_t hdr_len; 19238c2ecf20Sopenharmony_ci u8 da[ETH_ALEN]; 19248c2ecf20Sopenharmony_ci u8 sa[ETH_ALEN]; 19258c2ecf20Sopenharmony_ci u16 qos_ctl = 0; 19268c2ecf20Sopenharmony_ci u8 *qos; 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci /* copy SA & DA and pull decapped header */ 19298c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)msdu->data; 19308c2ecf20Sopenharmony_ci hdr_len = ieee80211_hdrlen(hdr->frame_control); 19318c2ecf20Sopenharmony_ci ether_addr_copy(da, ieee80211_get_DA(hdr)); 19328c2ecf20Sopenharmony_ci ether_addr_copy(sa, ieee80211_get_SA(hdr)); 19338c2ecf20Sopenharmony_ci skb_pull(msdu, ieee80211_hdrlen(hdr->frame_control)); 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci if (rxcb->is_first_msdu) { 19368c2ecf20Sopenharmony_ci /* original 802.11 header is valid for the first msdu 19378c2ecf20Sopenharmony_ci * hence we can reuse the same header 19388c2ecf20Sopenharmony_ci */ 19398c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)first_hdr; 19408c2ecf20Sopenharmony_ci hdr_len = ieee80211_hdrlen(hdr->frame_control); 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci /* Each A-MSDU subframe will be reported as a separate MSDU, 19438c2ecf20Sopenharmony_ci * so strip the A-MSDU bit from QoS Ctl. 19448c2ecf20Sopenharmony_ci */ 19458c2ecf20Sopenharmony_ci if (ieee80211_is_data_qos(hdr->frame_control)) { 19468c2ecf20Sopenharmony_ci qos = ieee80211_get_qos_ctl(hdr); 19478c2ecf20Sopenharmony_ci qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; 19488c2ecf20Sopenharmony_ci } 19498c2ecf20Sopenharmony_ci } else { 19508c2ecf20Sopenharmony_ci /* Rebuild qos header if this is a middle/last msdu */ 19518c2ecf20Sopenharmony_ci hdr->frame_control |= __cpu_to_le16(IEEE80211_STYPE_QOS_DATA); 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci /* Reset the order bit as the HT_Control header is stripped */ 19548c2ecf20Sopenharmony_ci hdr->frame_control &= ~(__cpu_to_le16(IEEE80211_FCTL_ORDER)); 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci qos_ctl = rxcb->tid; 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci if (ath11k_dp_rx_h_msdu_start_mesh_ctl_present(rxcb->rx_desc)) 19598c2ecf20Sopenharmony_ci qos_ctl |= IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci /* TODO Add other QoS ctl fields when required */ 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci /* copy decap header before overwriting for reuse below */ 19648c2ecf20Sopenharmony_ci memcpy(decap_hdr, (uint8_t *)hdr, hdr_len); 19658c2ecf20Sopenharmony_ci } 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_IV_STRIPPED)) { 19688c2ecf20Sopenharmony_ci memcpy(skb_push(msdu, 19698c2ecf20Sopenharmony_ci ath11k_dp_rx_crypto_param_len(ar, enctype)), 19708c2ecf20Sopenharmony_ci (void *)hdr + hdr_len, 19718c2ecf20Sopenharmony_ci ath11k_dp_rx_crypto_param_len(ar, enctype)); 19728c2ecf20Sopenharmony_ci } 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci if (!rxcb->is_first_msdu) { 19758c2ecf20Sopenharmony_ci memcpy(skb_push(msdu, 19768c2ecf20Sopenharmony_ci IEEE80211_QOS_CTL_LEN), &qos_ctl, 19778c2ecf20Sopenharmony_ci IEEE80211_QOS_CTL_LEN); 19788c2ecf20Sopenharmony_ci memcpy(skb_push(msdu, hdr_len), decap_hdr, hdr_len); 19798c2ecf20Sopenharmony_ci return; 19808c2ecf20Sopenharmony_ci } 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci /* original 802.11 header has a different DA and in 19858c2ecf20Sopenharmony_ci * case of 4addr it may also have different SA 19868c2ecf20Sopenharmony_ci */ 19878c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)msdu->data; 19888c2ecf20Sopenharmony_ci ether_addr_copy(ieee80211_get_DA(hdr), da); 19898c2ecf20Sopenharmony_ci ether_addr_copy(ieee80211_get_SA(hdr), sa); 19908c2ecf20Sopenharmony_ci} 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_undecap_raw(struct ath11k *ar, struct sk_buff *msdu, 19938c2ecf20Sopenharmony_ci enum hal_encrypt_type enctype, 19948c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status, 19958c2ecf20Sopenharmony_ci bool decrypted) 19968c2ecf20Sopenharmony_ci{ 19978c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 19988c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 19998c2ecf20Sopenharmony_ci size_t hdr_len; 20008c2ecf20Sopenharmony_ci size_t crypto_len; 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci if (!rxcb->is_first_msdu || 20038c2ecf20Sopenharmony_ci !(rxcb->is_first_msdu && rxcb->is_last_msdu)) { 20048c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 20058c2ecf20Sopenharmony_ci return; 20068c2ecf20Sopenharmony_ci } 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci skb_trim(msdu, msdu->len - FCS_LEN); 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci if (!decrypted) 20118c2ecf20Sopenharmony_ci return; 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci hdr = (void *)msdu->data; 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci /* Tail */ 20168c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_IV_STRIPPED) { 20178c2ecf20Sopenharmony_ci skb_trim(msdu, msdu->len - 20188c2ecf20Sopenharmony_ci ath11k_dp_rx_crypto_mic_len(ar, enctype)); 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci skb_trim(msdu, msdu->len - 20218c2ecf20Sopenharmony_ci ath11k_dp_rx_crypto_icv_len(ar, enctype)); 20228c2ecf20Sopenharmony_ci } else { 20238c2ecf20Sopenharmony_ci /* MIC */ 20248c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_MIC_STRIPPED) 20258c2ecf20Sopenharmony_ci skb_trim(msdu, msdu->len - 20268c2ecf20Sopenharmony_ci ath11k_dp_rx_crypto_mic_len(ar, enctype)); 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci /* ICV */ 20298c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_ICV_STRIPPED) 20308c2ecf20Sopenharmony_ci skb_trim(msdu, msdu->len - 20318c2ecf20Sopenharmony_ci ath11k_dp_rx_crypto_icv_len(ar, enctype)); 20328c2ecf20Sopenharmony_ci } 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci /* MMIC */ 20358c2ecf20Sopenharmony_ci if ((status->flag & RX_FLAG_MMIC_STRIPPED) && 20368c2ecf20Sopenharmony_ci !ieee80211_has_morefrags(hdr->frame_control) && 20378c2ecf20Sopenharmony_ci enctype == HAL_ENCRYPT_TYPE_TKIP_MIC) 20388c2ecf20Sopenharmony_ci skb_trim(msdu, msdu->len - IEEE80211_CCMP_MIC_LEN); 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci /* Head */ 20418c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_IV_STRIPPED) { 20428c2ecf20Sopenharmony_ci hdr_len = ieee80211_hdrlen(hdr->frame_control); 20438c2ecf20Sopenharmony_ci crypto_len = ath11k_dp_rx_crypto_param_len(ar, enctype); 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci memmove((void *)msdu->data + crypto_len, 20468c2ecf20Sopenharmony_ci (void *)msdu->data, hdr_len); 20478c2ecf20Sopenharmony_ci skb_pull(msdu, crypto_len); 20488c2ecf20Sopenharmony_ci } 20498c2ecf20Sopenharmony_ci} 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_cistatic void *ath11k_dp_rx_h_find_rfc1042(struct ath11k *ar, 20528c2ecf20Sopenharmony_ci struct sk_buff *msdu, 20538c2ecf20Sopenharmony_ci enum hal_encrypt_type enctype) 20548c2ecf20Sopenharmony_ci{ 20558c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 20568c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 20578c2ecf20Sopenharmony_ci size_t hdr_len, crypto_len; 20588c2ecf20Sopenharmony_ci void *rfc1042; 20598c2ecf20Sopenharmony_ci bool is_amsdu; 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci is_amsdu = !(rxcb->is_first_msdu && rxcb->is_last_msdu); 20628c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)ath11k_dp_rx_h_80211_hdr(rxcb->rx_desc); 20638c2ecf20Sopenharmony_ci rfc1042 = hdr; 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci if (rxcb->is_first_msdu) { 20668c2ecf20Sopenharmony_ci hdr_len = ieee80211_hdrlen(hdr->frame_control); 20678c2ecf20Sopenharmony_ci crypto_len = ath11k_dp_rx_crypto_param_len(ar, enctype); 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci rfc1042 += hdr_len + crypto_len; 20708c2ecf20Sopenharmony_ci } 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci if (is_amsdu) 20738c2ecf20Sopenharmony_ci rfc1042 += sizeof(struct ath11k_dp_amsdu_subframe_hdr); 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci return rfc1042; 20768c2ecf20Sopenharmony_ci} 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_undecap_eth(struct ath11k *ar, 20798c2ecf20Sopenharmony_ci struct sk_buff *msdu, 20808c2ecf20Sopenharmony_ci u8 *first_hdr, 20818c2ecf20Sopenharmony_ci enum hal_encrypt_type enctype, 20828c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status) 20838c2ecf20Sopenharmony_ci{ 20848c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 20858c2ecf20Sopenharmony_ci struct ethhdr *eth; 20868c2ecf20Sopenharmony_ci size_t hdr_len; 20878c2ecf20Sopenharmony_ci u8 da[ETH_ALEN]; 20888c2ecf20Sopenharmony_ci u8 sa[ETH_ALEN]; 20898c2ecf20Sopenharmony_ci void *rfc1042; 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci rfc1042 = ath11k_dp_rx_h_find_rfc1042(ar, msdu, enctype); 20928c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!rfc1042)) 20938c2ecf20Sopenharmony_ci return; 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci /* pull decapped header and copy SA & DA */ 20968c2ecf20Sopenharmony_ci eth = (struct ethhdr *)msdu->data; 20978c2ecf20Sopenharmony_ci ether_addr_copy(da, eth->h_dest); 20988c2ecf20Sopenharmony_ci ether_addr_copy(sa, eth->h_source); 20998c2ecf20Sopenharmony_ci skb_pull(msdu, sizeof(struct ethhdr)); 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci /* push rfc1042/llc/snap */ 21028c2ecf20Sopenharmony_ci memcpy(skb_push(msdu, sizeof(struct ath11k_dp_rfc1042_hdr)), rfc1042, 21038c2ecf20Sopenharmony_ci sizeof(struct ath11k_dp_rfc1042_hdr)); 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci /* push original 802.11 header */ 21068c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)first_hdr; 21078c2ecf20Sopenharmony_ci hdr_len = ieee80211_hdrlen(hdr->frame_control); 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_IV_STRIPPED)) { 21108c2ecf20Sopenharmony_ci memcpy(skb_push(msdu, 21118c2ecf20Sopenharmony_ci ath11k_dp_rx_crypto_param_len(ar, enctype)), 21128c2ecf20Sopenharmony_ci (void *)hdr + hdr_len, 21138c2ecf20Sopenharmony_ci ath11k_dp_rx_crypto_param_len(ar, enctype)); 21148c2ecf20Sopenharmony_ci } 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci /* original 802.11 header has a different DA and in 21198c2ecf20Sopenharmony_ci * case of 4addr it may also have different SA 21208c2ecf20Sopenharmony_ci */ 21218c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)msdu->data; 21228c2ecf20Sopenharmony_ci ether_addr_copy(ieee80211_get_DA(hdr), da); 21238c2ecf20Sopenharmony_ci ether_addr_copy(ieee80211_get_SA(hdr), sa); 21248c2ecf20Sopenharmony_ci} 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_undecap(struct ath11k *ar, struct sk_buff *msdu, 21278c2ecf20Sopenharmony_ci struct hal_rx_desc *rx_desc, 21288c2ecf20Sopenharmony_ci enum hal_encrypt_type enctype, 21298c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status, 21308c2ecf20Sopenharmony_ci bool decrypted) 21318c2ecf20Sopenharmony_ci{ 21328c2ecf20Sopenharmony_ci u8 *first_hdr; 21338c2ecf20Sopenharmony_ci u8 decap; 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci first_hdr = ath11k_dp_rx_h_80211_hdr(rx_desc); 21368c2ecf20Sopenharmony_ci decap = ath11k_dp_rx_h_msdu_start_decap_type(rx_desc); 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci switch (decap) { 21398c2ecf20Sopenharmony_ci case DP_RX_DECAP_TYPE_NATIVE_WIFI: 21408c2ecf20Sopenharmony_ci ath11k_dp_rx_h_undecap_nwifi(ar, msdu, first_hdr, 21418c2ecf20Sopenharmony_ci enctype, status); 21428c2ecf20Sopenharmony_ci break; 21438c2ecf20Sopenharmony_ci case DP_RX_DECAP_TYPE_RAW: 21448c2ecf20Sopenharmony_ci ath11k_dp_rx_h_undecap_raw(ar, msdu, enctype, status, 21458c2ecf20Sopenharmony_ci decrypted); 21468c2ecf20Sopenharmony_ci break; 21478c2ecf20Sopenharmony_ci case DP_RX_DECAP_TYPE_ETHERNET2_DIX: 21488c2ecf20Sopenharmony_ci /* TODO undecap support for middle/last msdu's of amsdu */ 21498c2ecf20Sopenharmony_ci ath11k_dp_rx_h_undecap_eth(ar, msdu, first_hdr, 21508c2ecf20Sopenharmony_ci enctype, status); 21518c2ecf20Sopenharmony_ci break; 21528c2ecf20Sopenharmony_ci case DP_RX_DECAP_TYPE_8023: 21538c2ecf20Sopenharmony_ci /* TODO: Handle undecap for these formats */ 21548c2ecf20Sopenharmony_ci break; 21558c2ecf20Sopenharmony_ci } 21568c2ecf20Sopenharmony_ci} 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_mpdu(struct ath11k *ar, 21598c2ecf20Sopenharmony_ci struct sk_buff *msdu, 21608c2ecf20Sopenharmony_ci struct hal_rx_desc *rx_desc, 21618c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rx_status) 21628c2ecf20Sopenharmony_ci{ 21638c2ecf20Sopenharmony_ci bool fill_crypto_hdr, mcast; 21648c2ecf20Sopenharmony_ci enum hal_encrypt_type enctype; 21658c2ecf20Sopenharmony_ci bool is_decrypted = false; 21668c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 21678c2ecf20Sopenharmony_ci struct ath11k_peer *peer; 21688c2ecf20Sopenharmony_ci u32 err_bitmap; 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)msdu->data; 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci /* PN for multicast packets will be checked in mac80211 */ 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci mcast = is_multicast_ether_addr(hdr->addr1); 21758c2ecf20Sopenharmony_ci fill_crypto_hdr = mcast; 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci spin_lock_bh(&ar->ab->base_lock); 21788c2ecf20Sopenharmony_ci peer = ath11k_peer_find_by_addr(ar->ab, hdr->addr2); 21798c2ecf20Sopenharmony_ci if (peer) { 21808c2ecf20Sopenharmony_ci if (mcast) 21818c2ecf20Sopenharmony_ci enctype = peer->sec_type_grp; 21828c2ecf20Sopenharmony_ci else 21838c2ecf20Sopenharmony_ci enctype = peer->sec_type; 21848c2ecf20Sopenharmony_ci } else { 21858c2ecf20Sopenharmony_ci enctype = HAL_ENCRYPT_TYPE_OPEN; 21868c2ecf20Sopenharmony_ci } 21878c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->ab->base_lock); 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci err_bitmap = ath11k_dp_rx_h_attn_mpdu_err(rx_desc); 21908c2ecf20Sopenharmony_ci if (enctype != HAL_ENCRYPT_TYPE_OPEN && !err_bitmap) 21918c2ecf20Sopenharmony_ci is_decrypted = ath11k_dp_rx_h_attn_is_decrypted(rx_desc); 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci /* Clear per-MPDU flags while leaving per-PPDU flags intact */ 21948c2ecf20Sopenharmony_ci rx_status->flag &= ~(RX_FLAG_FAILED_FCS_CRC | 21958c2ecf20Sopenharmony_ci RX_FLAG_MMIC_ERROR | 21968c2ecf20Sopenharmony_ci RX_FLAG_DECRYPTED | 21978c2ecf20Sopenharmony_ci RX_FLAG_IV_STRIPPED | 21988c2ecf20Sopenharmony_ci RX_FLAG_MMIC_STRIPPED); 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci if (err_bitmap & DP_RX_MPDU_ERR_FCS) 22018c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; 22028c2ecf20Sopenharmony_ci if (err_bitmap & DP_RX_MPDU_ERR_TKIP_MIC) 22038c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_MMIC_ERROR; 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_ci if (is_decrypted) { 22068c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_MMIC_STRIPPED; 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci if (fill_crypto_hdr) 22098c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_MIC_STRIPPED | 22108c2ecf20Sopenharmony_ci RX_FLAG_ICV_STRIPPED; 22118c2ecf20Sopenharmony_ci else 22128c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_IV_STRIPPED | 22138c2ecf20Sopenharmony_ci RX_FLAG_PN_VALIDATED; 22148c2ecf20Sopenharmony_ci } 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci ath11k_dp_rx_h_csum_offload(msdu); 22178c2ecf20Sopenharmony_ci ath11k_dp_rx_h_undecap(ar, msdu, rx_desc, 22188c2ecf20Sopenharmony_ci enctype, rx_status, is_decrypted); 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci if (!is_decrypted || fill_crypto_hdr) 22218c2ecf20Sopenharmony_ci return; 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci hdr = (void *)msdu->data; 22248c2ecf20Sopenharmony_ci hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); 22258c2ecf20Sopenharmony_ci} 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_rate(struct ath11k *ar, struct hal_rx_desc *rx_desc, 22288c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rx_status) 22298c2ecf20Sopenharmony_ci{ 22308c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 22318c2ecf20Sopenharmony_ci enum rx_msdu_start_pkt_type pkt_type; 22328c2ecf20Sopenharmony_ci u8 bw; 22338c2ecf20Sopenharmony_ci u8 rate_mcs, nss; 22348c2ecf20Sopenharmony_ci u8 sgi; 22358c2ecf20Sopenharmony_ci bool is_cck; 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci pkt_type = ath11k_dp_rx_h_msdu_start_pkt_type(rx_desc); 22388c2ecf20Sopenharmony_ci bw = ath11k_dp_rx_h_msdu_start_rx_bw(rx_desc); 22398c2ecf20Sopenharmony_ci rate_mcs = ath11k_dp_rx_h_msdu_start_rate_mcs(rx_desc); 22408c2ecf20Sopenharmony_ci nss = ath11k_dp_rx_h_msdu_start_nss(rx_desc); 22418c2ecf20Sopenharmony_ci sgi = ath11k_dp_rx_h_msdu_start_sgi(rx_desc); 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci switch (pkt_type) { 22448c2ecf20Sopenharmony_ci case RX_MSDU_START_PKT_TYPE_11A: 22458c2ecf20Sopenharmony_ci case RX_MSDU_START_PKT_TYPE_11B: 22468c2ecf20Sopenharmony_ci is_cck = (pkt_type == RX_MSDU_START_PKT_TYPE_11B); 22478c2ecf20Sopenharmony_ci sband = &ar->mac.sbands[rx_status->band]; 22488c2ecf20Sopenharmony_ci rx_status->rate_idx = ath11k_mac_hw_rate_to_idx(sband, rate_mcs, 22498c2ecf20Sopenharmony_ci is_cck); 22508c2ecf20Sopenharmony_ci break; 22518c2ecf20Sopenharmony_ci case RX_MSDU_START_PKT_TYPE_11N: 22528c2ecf20Sopenharmony_ci rx_status->encoding = RX_ENC_HT; 22538c2ecf20Sopenharmony_ci if (rate_mcs > ATH11K_HT_MCS_MAX) { 22548c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, 22558c2ecf20Sopenharmony_ci "Received with invalid mcs in HT mode %d\n", 22568c2ecf20Sopenharmony_ci rate_mcs); 22578c2ecf20Sopenharmony_ci break; 22588c2ecf20Sopenharmony_ci } 22598c2ecf20Sopenharmony_ci rx_status->rate_idx = rate_mcs + (8 * (nss - 1)); 22608c2ecf20Sopenharmony_ci if (sgi) 22618c2ecf20Sopenharmony_ci rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; 22628c2ecf20Sopenharmony_ci rx_status->bw = ath11k_mac_bw_to_mac80211_bw(bw); 22638c2ecf20Sopenharmony_ci break; 22648c2ecf20Sopenharmony_ci case RX_MSDU_START_PKT_TYPE_11AC: 22658c2ecf20Sopenharmony_ci rx_status->encoding = RX_ENC_VHT; 22668c2ecf20Sopenharmony_ci rx_status->rate_idx = rate_mcs; 22678c2ecf20Sopenharmony_ci if (rate_mcs > ATH11K_VHT_MCS_MAX) { 22688c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, 22698c2ecf20Sopenharmony_ci "Received with invalid mcs in VHT mode %d\n", 22708c2ecf20Sopenharmony_ci rate_mcs); 22718c2ecf20Sopenharmony_ci break; 22728c2ecf20Sopenharmony_ci } 22738c2ecf20Sopenharmony_ci rx_status->nss = nss; 22748c2ecf20Sopenharmony_ci if (sgi) 22758c2ecf20Sopenharmony_ci rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; 22768c2ecf20Sopenharmony_ci rx_status->bw = ath11k_mac_bw_to_mac80211_bw(bw); 22778c2ecf20Sopenharmony_ci break; 22788c2ecf20Sopenharmony_ci case RX_MSDU_START_PKT_TYPE_11AX: 22798c2ecf20Sopenharmony_ci rx_status->rate_idx = rate_mcs; 22808c2ecf20Sopenharmony_ci if (rate_mcs > ATH11K_HE_MCS_MAX) { 22818c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, 22828c2ecf20Sopenharmony_ci "Received with invalid mcs in HE mode %d\n", 22838c2ecf20Sopenharmony_ci rate_mcs); 22848c2ecf20Sopenharmony_ci break; 22858c2ecf20Sopenharmony_ci } 22868c2ecf20Sopenharmony_ci rx_status->encoding = RX_ENC_HE; 22878c2ecf20Sopenharmony_ci rx_status->nss = nss; 22888c2ecf20Sopenharmony_ci rx_status->he_gi = ath11k_he_gi_to_nl80211_he_gi(sgi); 22898c2ecf20Sopenharmony_ci rx_status->bw = ath11k_mac_bw_to_mac80211_bw(bw); 22908c2ecf20Sopenharmony_ci break; 22918c2ecf20Sopenharmony_ci } 22928c2ecf20Sopenharmony_ci} 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_ppdu(struct ath11k *ar, struct hal_rx_desc *rx_desc, 22958c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rx_status) 22968c2ecf20Sopenharmony_ci{ 22978c2ecf20Sopenharmony_ci u8 channel_num; 22988c2ecf20Sopenharmony_ci u32 center_freq; 22998c2ecf20Sopenharmony_ci struct ieee80211_channel *channel; 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci rx_status->freq = 0; 23028c2ecf20Sopenharmony_ci rx_status->rate_idx = 0; 23038c2ecf20Sopenharmony_ci rx_status->nss = 0; 23048c2ecf20Sopenharmony_ci rx_status->encoding = RX_ENC_LEGACY; 23058c2ecf20Sopenharmony_ci rx_status->bw = RATE_INFO_BW_20; 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci channel_num = ath11k_dp_rx_h_msdu_start_freq(rx_desc); 23108c2ecf20Sopenharmony_ci center_freq = ath11k_dp_rx_h_msdu_start_freq(rx_desc) >> 16; 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci if (center_freq >= ATH11K_MIN_6G_FREQ && 23138c2ecf20Sopenharmony_ci center_freq <= ATH11K_MAX_6G_FREQ) { 23148c2ecf20Sopenharmony_ci rx_status->band = NL80211_BAND_6GHZ; 23158c2ecf20Sopenharmony_ci rx_status->freq = center_freq; 23168c2ecf20Sopenharmony_ci } else if (channel_num >= 1 && channel_num <= 14) { 23178c2ecf20Sopenharmony_ci rx_status->band = NL80211_BAND_2GHZ; 23188c2ecf20Sopenharmony_ci } else if (channel_num >= 36 && channel_num <= 173) { 23198c2ecf20Sopenharmony_ci rx_status->band = NL80211_BAND_5GHZ; 23208c2ecf20Sopenharmony_ci } else { 23218c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 23228c2ecf20Sopenharmony_ci channel = ar->rx_channel; 23238c2ecf20Sopenharmony_ci if (channel) { 23248c2ecf20Sopenharmony_ci rx_status->band = channel->band; 23258c2ecf20Sopenharmony_ci channel_num = 23268c2ecf20Sopenharmony_ci ieee80211_frequency_to_channel(channel->center_freq); 23278c2ecf20Sopenharmony_ci } 23288c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 23298c2ecf20Sopenharmony_ci ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "rx_desc: ", 23308c2ecf20Sopenharmony_ci rx_desc, sizeof(struct hal_rx_desc)); 23318c2ecf20Sopenharmony_ci } 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci if (rx_status->band != NL80211_BAND_6GHZ) 23348c2ecf20Sopenharmony_ci rx_status->freq = ieee80211_channel_to_frequency(channel_num, 23358c2ecf20Sopenharmony_ci rx_status->band); 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci ath11k_dp_rx_h_rate(ar, rx_desc, rx_status); 23388c2ecf20Sopenharmony_ci} 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_cistatic char *ath11k_print_get_tid(struct ieee80211_hdr *hdr, char *out, 23418c2ecf20Sopenharmony_ci size_t size) 23428c2ecf20Sopenharmony_ci{ 23438c2ecf20Sopenharmony_ci u8 *qc; 23448c2ecf20Sopenharmony_ci int tid; 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci if (!ieee80211_is_data_qos(hdr->frame_control)) 23478c2ecf20Sopenharmony_ci return ""; 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci qc = ieee80211_get_qos_ctl(hdr); 23508c2ecf20Sopenharmony_ci tid = *qc & IEEE80211_QOS_CTL_TID_MASK; 23518c2ecf20Sopenharmony_ci snprintf(out, size, "tid %d", tid); 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci return out; 23548c2ecf20Sopenharmony_ci} 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_deliver_msdu(struct ath11k *ar, struct napi_struct *napi, 23578c2ecf20Sopenharmony_ci struct sk_buff *msdu) 23588c2ecf20Sopenharmony_ci{ 23598c2ecf20Sopenharmony_ci static const struct ieee80211_radiotap_he known = { 23608c2ecf20Sopenharmony_ci .data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | 23618c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN), 23628c2ecf20Sopenharmony_ci .data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN), 23638c2ecf20Sopenharmony_ci }; 23648c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status; 23658c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; 23668c2ecf20Sopenharmony_ci struct ieee80211_radiotap_he *he = NULL; 23678c2ecf20Sopenharmony_ci char tid[32]; 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci status = IEEE80211_SKB_RXCB(msdu); 23708c2ecf20Sopenharmony_ci if (status->encoding == RX_ENC_HE) { 23718c2ecf20Sopenharmony_ci he = skb_push(msdu, sizeof(known)); 23728c2ecf20Sopenharmony_ci memcpy(he, &known, sizeof(known)); 23738c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_RADIOTAP_HE; 23748c2ecf20Sopenharmony_ci } 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 23778c2ecf20Sopenharmony_ci "rx skb %pK len %u peer %pM %s %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", 23788c2ecf20Sopenharmony_ci msdu, 23798c2ecf20Sopenharmony_ci msdu->len, 23808c2ecf20Sopenharmony_ci ieee80211_get_SA(hdr), 23818c2ecf20Sopenharmony_ci ath11k_print_get_tid(hdr, tid, sizeof(tid)), 23828c2ecf20Sopenharmony_ci is_multicast_ether_addr(ieee80211_get_DA(hdr)) ? 23838c2ecf20Sopenharmony_ci "mcast" : "ucast", 23848c2ecf20Sopenharmony_ci (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4, 23858c2ecf20Sopenharmony_ci (status->encoding == RX_ENC_LEGACY) ? "legacy" : "", 23868c2ecf20Sopenharmony_ci (status->encoding == RX_ENC_HT) ? "ht" : "", 23878c2ecf20Sopenharmony_ci (status->encoding == RX_ENC_VHT) ? "vht" : "", 23888c2ecf20Sopenharmony_ci (status->encoding == RX_ENC_HE) ? "he" : "", 23898c2ecf20Sopenharmony_ci (status->bw == RATE_INFO_BW_40) ? "40" : "", 23908c2ecf20Sopenharmony_ci (status->bw == RATE_INFO_BW_80) ? "80" : "", 23918c2ecf20Sopenharmony_ci (status->bw == RATE_INFO_BW_160) ? "160" : "", 23928c2ecf20Sopenharmony_ci status->enc_flags & RX_ENC_FLAG_SHORT_GI ? "sgi " : "", 23938c2ecf20Sopenharmony_ci status->rate_idx, 23948c2ecf20Sopenharmony_ci status->nss, 23958c2ecf20Sopenharmony_ci status->freq, 23968c2ecf20Sopenharmony_ci status->band, status->flag, 23978c2ecf20Sopenharmony_ci !!(status->flag & RX_FLAG_FAILED_FCS_CRC), 23988c2ecf20Sopenharmony_ci !!(status->flag & RX_FLAG_MMIC_ERROR), 23998c2ecf20Sopenharmony_ci !!(status->flag & RX_FLAG_AMSDU_MORE)); 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_ci ath11k_dbg_dump(ar->ab, ATH11K_DBG_DP_RX, NULL, "dp rx msdu: ", 24028c2ecf20Sopenharmony_ci msdu->data, msdu->len); 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci /* TODO: trace rx packet */ 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci ieee80211_rx_napi(ar->hw, NULL, msdu, napi); 24078c2ecf20Sopenharmony_ci} 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_process_msdu(struct ath11k *ar, 24108c2ecf20Sopenharmony_ci struct sk_buff *msdu, 24118c2ecf20Sopenharmony_ci struct sk_buff_head *msdu_list) 24128c2ecf20Sopenharmony_ci{ 24138c2ecf20Sopenharmony_ci struct hal_rx_desc *rx_desc, *lrx_desc; 24148c2ecf20Sopenharmony_ci struct ieee80211_rx_status rx_status = {0}; 24158c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status; 24168c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb; 24178c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 24188c2ecf20Sopenharmony_ci struct sk_buff *last_buf; 24198c2ecf20Sopenharmony_ci u8 l3_pad_bytes; 24208c2ecf20Sopenharmony_ci u8 *hdr_status; 24218c2ecf20Sopenharmony_ci u16 msdu_len; 24228c2ecf20Sopenharmony_ci int ret; 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci last_buf = ath11k_dp_rx_get_msdu_last_buf(msdu_list, msdu); 24258c2ecf20Sopenharmony_ci if (!last_buf) { 24268c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, 24278c2ecf20Sopenharmony_ci "No valid Rx buffer to access Atten/MSDU_END/MPDU_END tlvs\n"); 24288c2ecf20Sopenharmony_ci ret = -EIO; 24298c2ecf20Sopenharmony_ci goto free_out; 24308c2ecf20Sopenharmony_ci } 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci rx_desc = (struct hal_rx_desc *)msdu->data; 24338c2ecf20Sopenharmony_ci lrx_desc = (struct hal_rx_desc *)last_buf->data; 24348c2ecf20Sopenharmony_ci if (!ath11k_dp_rx_h_attn_msdu_done(lrx_desc)) { 24358c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "msdu_done bit in attention is not set\n"); 24368c2ecf20Sopenharmony_ci ret = -EIO; 24378c2ecf20Sopenharmony_ci goto free_out; 24388c2ecf20Sopenharmony_ci } 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci rxcb = ATH11K_SKB_RXCB(msdu); 24418c2ecf20Sopenharmony_ci rxcb->rx_desc = rx_desc; 24428c2ecf20Sopenharmony_ci msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(rx_desc); 24438c2ecf20Sopenharmony_ci l3_pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(lrx_desc); 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci if (rxcb->is_frag) { 24468c2ecf20Sopenharmony_ci skb_pull(msdu, HAL_RX_DESC_SIZE); 24478c2ecf20Sopenharmony_ci } else if (!rxcb->is_continuation) { 24488c2ecf20Sopenharmony_ci if ((msdu_len + HAL_RX_DESC_SIZE) > DP_RX_BUFFER_SIZE) { 24498c2ecf20Sopenharmony_ci hdr_status = ath11k_dp_rx_h_80211_hdr(rx_desc); 24508c2ecf20Sopenharmony_ci ret = -EINVAL; 24518c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "invalid msdu len %u\n", msdu_len); 24528c2ecf20Sopenharmony_ci ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", hdr_status, 24538c2ecf20Sopenharmony_ci sizeof(struct ieee80211_hdr)); 24548c2ecf20Sopenharmony_ci ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", rx_desc, 24558c2ecf20Sopenharmony_ci sizeof(struct hal_rx_desc)); 24568c2ecf20Sopenharmony_ci goto free_out; 24578c2ecf20Sopenharmony_ci } 24588c2ecf20Sopenharmony_ci skb_put(msdu, HAL_RX_DESC_SIZE + l3_pad_bytes + msdu_len); 24598c2ecf20Sopenharmony_ci skb_pull(msdu, HAL_RX_DESC_SIZE + l3_pad_bytes); 24608c2ecf20Sopenharmony_ci } else { 24618c2ecf20Sopenharmony_ci ret = ath11k_dp_rx_msdu_coalesce(ar, msdu_list, 24628c2ecf20Sopenharmony_ci msdu, last_buf, 24638c2ecf20Sopenharmony_ci l3_pad_bytes, msdu_len); 24648c2ecf20Sopenharmony_ci if (ret) { 24658c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, 24668c2ecf20Sopenharmony_ci "failed to coalesce msdu rx buffer%d\n", ret); 24678c2ecf20Sopenharmony_ci goto free_out; 24688c2ecf20Sopenharmony_ci } 24698c2ecf20Sopenharmony_ci } 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)msdu->data; 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci /* Process only data frames */ 24748c2ecf20Sopenharmony_ci if (!ieee80211_is_data(hdr->frame_control)) 24758c2ecf20Sopenharmony_ci return -EINVAL; 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_ci ath11k_dp_rx_h_ppdu(ar, rx_desc, &rx_status); 24788c2ecf20Sopenharmony_ci ath11k_dp_rx_h_mpdu(ar, msdu, rx_desc, &rx_status); 24798c2ecf20Sopenharmony_ci 24808c2ecf20Sopenharmony_ci rx_status.flag |= RX_FLAG_SKIP_MONITOR | RX_FLAG_DUP_VALIDATED; 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci status = IEEE80211_SKB_RXCB(msdu); 24838c2ecf20Sopenharmony_ci *status = rx_status; 24848c2ecf20Sopenharmony_ci return 0; 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_cifree_out: 24878c2ecf20Sopenharmony_ci return ret; 24888c2ecf20Sopenharmony_ci} 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_process_received_packets(struct ath11k_base *ab, 24918c2ecf20Sopenharmony_ci struct napi_struct *napi, 24928c2ecf20Sopenharmony_ci struct sk_buff_head *msdu_list, 24938c2ecf20Sopenharmony_ci int *quota, int ring_id) 24948c2ecf20Sopenharmony_ci{ 24958c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb; 24968c2ecf20Sopenharmony_ci struct sk_buff *msdu; 24978c2ecf20Sopenharmony_ci struct ath11k *ar; 24988c2ecf20Sopenharmony_ci u8 mac_id; 24998c2ecf20Sopenharmony_ci int ret; 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_ci if (skb_queue_empty(msdu_list)) 25028c2ecf20Sopenharmony_ci return; 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_ci rcu_read_lock(); 25058c2ecf20Sopenharmony_ci 25068c2ecf20Sopenharmony_ci while (*quota && (msdu = __skb_dequeue(msdu_list))) { 25078c2ecf20Sopenharmony_ci rxcb = ATH11K_SKB_RXCB(msdu); 25088c2ecf20Sopenharmony_ci mac_id = rxcb->mac_id; 25098c2ecf20Sopenharmony_ci ar = ab->pdevs[mac_id].ar; 25108c2ecf20Sopenharmony_ci if (!rcu_dereference(ab->pdevs_active[mac_id])) { 25118c2ecf20Sopenharmony_ci dev_kfree_skb_any(msdu); 25128c2ecf20Sopenharmony_ci continue; 25138c2ecf20Sopenharmony_ci } 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) { 25168c2ecf20Sopenharmony_ci dev_kfree_skb_any(msdu); 25178c2ecf20Sopenharmony_ci continue; 25188c2ecf20Sopenharmony_ci } 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci ret = ath11k_dp_rx_process_msdu(ar, msdu, msdu_list); 25218c2ecf20Sopenharmony_ci if (ret) { 25228c2ecf20Sopenharmony_ci ath11k_dbg(ab, ATH11K_DBG_DATA, 25238c2ecf20Sopenharmony_ci "Unable to process msdu %d", ret); 25248c2ecf20Sopenharmony_ci dev_kfree_skb_any(msdu); 25258c2ecf20Sopenharmony_ci continue; 25268c2ecf20Sopenharmony_ci } 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci ath11k_dp_rx_deliver_msdu(ar, napi, msdu); 25298c2ecf20Sopenharmony_ci (*quota)--; 25308c2ecf20Sopenharmony_ci } 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci rcu_read_unlock(); 25338c2ecf20Sopenharmony_ci} 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ciint ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, 25368c2ecf20Sopenharmony_ci struct napi_struct *napi, int budget) 25378c2ecf20Sopenharmony_ci{ 25388c2ecf20Sopenharmony_ci struct ath11k_dp *dp = &ab->dp; 25398c2ecf20Sopenharmony_ci struct dp_rxdma_ring *rx_ring; 25408c2ecf20Sopenharmony_ci int num_buffs_reaped[MAX_RADIOS] = {0}; 25418c2ecf20Sopenharmony_ci struct sk_buff_head msdu_list; 25428c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb; 25438c2ecf20Sopenharmony_ci int total_msdu_reaped = 0; 25448c2ecf20Sopenharmony_ci struct hal_srng *srng; 25458c2ecf20Sopenharmony_ci struct sk_buff *msdu; 25468c2ecf20Sopenharmony_ci int quota = budget; 25478c2ecf20Sopenharmony_ci bool done = false; 25488c2ecf20Sopenharmony_ci int buf_id, mac_id; 25498c2ecf20Sopenharmony_ci struct ath11k *ar; 25508c2ecf20Sopenharmony_ci u32 *rx_desc; 25518c2ecf20Sopenharmony_ci int i; 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci __skb_queue_head_init(&msdu_list); 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci srng = &ab->hal.srng_list[dp->reo_dst_ring[ring_id].ring_id]; 25568c2ecf20Sopenharmony_ci 25578c2ecf20Sopenharmony_ci spin_lock_bh(&srng->lock); 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_ci ath11k_hal_srng_access_begin(ab, srng); 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_citry_again: 25628c2ecf20Sopenharmony_ci while ((rx_desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) { 25638c2ecf20Sopenharmony_ci struct hal_reo_dest_ring desc = *(struct hal_reo_dest_ring *)rx_desc; 25648c2ecf20Sopenharmony_ci enum hal_reo_dest_ring_push_reason push_reason; 25658c2ecf20Sopenharmony_ci u32 cookie; 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, 25688c2ecf20Sopenharmony_ci desc.buf_addr_info.info1); 25698c2ecf20Sopenharmony_ci buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, 25708c2ecf20Sopenharmony_ci cookie); 25718c2ecf20Sopenharmony_ci mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, cookie); 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci if (unlikely(buf_id == 0)) 25748c2ecf20Sopenharmony_ci continue; 25758c2ecf20Sopenharmony_ci 25768c2ecf20Sopenharmony_ci ar = ab->pdevs[mac_id].ar; 25778c2ecf20Sopenharmony_ci rx_ring = &ar->dp.rx_refill_buf_ring; 25788c2ecf20Sopenharmony_ci spin_lock_bh(&rx_ring->idr_lock); 25798c2ecf20Sopenharmony_ci msdu = idr_find(&rx_ring->bufs_idr, buf_id); 25808c2ecf20Sopenharmony_ci if (!msdu) { 25818c2ecf20Sopenharmony_ci ath11k_warn(ab, "frame rx with invalid buf_id %d\n", 25828c2ecf20Sopenharmony_ci buf_id); 25838c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 25848c2ecf20Sopenharmony_ci continue; 25858c2ecf20Sopenharmony_ci } 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci idr_remove(&rx_ring->bufs_idr, buf_id); 25888c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci rxcb = ATH11K_SKB_RXCB(msdu); 25918c2ecf20Sopenharmony_ci dma_unmap_single(ab->dev, rxcb->paddr, 25928c2ecf20Sopenharmony_ci msdu->len + skb_tailroom(msdu), 25938c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci num_buffs_reaped[mac_id]++; 25968c2ecf20Sopenharmony_ci total_msdu_reaped++; 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON, 25998c2ecf20Sopenharmony_ci desc.info0); 26008c2ecf20Sopenharmony_ci if (push_reason != 26018c2ecf20Sopenharmony_ci HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) { 26028c2ecf20Sopenharmony_ci dev_kfree_skb_any(msdu); 26038c2ecf20Sopenharmony_ci ab->soc_stats.hal_reo_error[dp->reo_dst_ring[ring_id].ring_id]++; 26048c2ecf20Sopenharmony_ci continue; 26058c2ecf20Sopenharmony_ci } 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_ci rxcb->is_first_msdu = !!(desc.rx_msdu_info.info0 & 26088c2ecf20Sopenharmony_ci RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU); 26098c2ecf20Sopenharmony_ci rxcb->is_last_msdu = !!(desc.rx_msdu_info.info0 & 26108c2ecf20Sopenharmony_ci RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU); 26118c2ecf20Sopenharmony_ci rxcb->is_continuation = !!(desc.rx_msdu_info.info0 & 26128c2ecf20Sopenharmony_ci RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); 26138c2ecf20Sopenharmony_ci rxcb->mac_id = mac_id; 26148c2ecf20Sopenharmony_ci rxcb->tid = FIELD_GET(HAL_REO_DEST_RING_INFO0_RX_QUEUE_NUM, 26158c2ecf20Sopenharmony_ci desc.info0); 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_ci __skb_queue_tail(&msdu_list, msdu); 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci if (total_msdu_reaped >= quota && !rxcb->is_continuation) { 26208c2ecf20Sopenharmony_ci done = true; 26218c2ecf20Sopenharmony_ci break; 26228c2ecf20Sopenharmony_ci } 26238c2ecf20Sopenharmony_ci } 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci /* Hw might have updated the head pointer after we cached it. 26268c2ecf20Sopenharmony_ci * In this case, even though there are entries in the ring we'll 26278c2ecf20Sopenharmony_ci * get rx_desc NULL. Give the read another try with updated cached 26288c2ecf20Sopenharmony_ci * head pointer so that we can reap complete MPDU in the current 26298c2ecf20Sopenharmony_ci * rx processing. 26308c2ecf20Sopenharmony_ci */ 26318c2ecf20Sopenharmony_ci if (!done && ath11k_hal_srng_dst_num_free(ab, srng, true)) { 26328c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 26338c2ecf20Sopenharmony_ci goto try_again; 26348c2ecf20Sopenharmony_ci } 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci spin_unlock_bh(&srng->lock); 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_ci if (!total_msdu_reaped) 26418c2ecf20Sopenharmony_ci goto exit; 26428c2ecf20Sopenharmony_ci 26438c2ecf20Sopenharmony_ci for (i = 0; i < ab->num_radios; i++) { 26448c2ecf20Sopenharmony_ci if (!num_buffs_reaped[i]) 26458c2ecf20Sopenharmony_ci continue; 26468c2ecf20Sopenharmony_ci 26478c2ecf20Sopenharmony_ci ar = ab->pdevs[i].ar; 26488c2ecf20Sopenharmony_ci rx_ring = &ar->dp.rx_refill_buf_ring; 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_ci ath11k_dp_rxbufs_replenish(ab, i, rx_ring, num_buffs_reaped[i], 26518c2ecf20Sopenharmony_ci HAL_RX_BUF_RBM_SW3_BM); 26528c2ecf20Sopenharmony_ci } 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci ath11k_dp_rx_process_received_packets(ab, napi, &msdu_list, 26558c2ecf20Sopenharmony_ci "a, ring_id); 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_ciexit: 26588c2ecf20Sopenharmony_ci return budget - quota; 26598c2ecf20Sopenharmony_ci} 26608c2ecf20Sopenharmony_ci 26618c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_update_peer_stats(struct ath11k_sta *arsta, 26628c2ecf20Sopenharmony_ci struct hal_rx_mon_ppdu_info *ppdu_info) 26638c2ecf20Sopenharmony_ci{ 26648c2ecf20Sopenharmony_ci struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats; 26658c2ecf20Sopenharmony_ci u32 num_msdu; 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci if (!rx_stats) 26688c2ecf20Sopenharmony_ci return; 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci num_msdu = ppdu_info->tcp_msdu_count + ppdu_info->tcp_ack_msdu_count + 26718c2ecf20Sopenharmony_ci ppdu_info->udp_msdu_count + ppdu_info->other_msdu_count; 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci rx_stats->num_msdu += num_msdu; 26748c2ecf20Sopenharmony_ci rx_stats->tcp_msdu_count += ppdu_info->tcp_msdu_count + 26758c2ecf20Sopenharmony_ci ppdu_info->tcp_ack_msdu_count; 26768c2ecf20Sopenharmony_ci rx_stats->udp_msdu_count += ppdu_info->udp_msdu_count; 26778c2ecf20Sopenharmony_ci rx_stats->other_msdu_count += ppdu_info->other_msdu_count; 26788c2ecf20Sopenharmony_ci 26798c2ecf20Sopenharmony_ci if (ppdu_info->preamble_type == HAL_RX_PREAMBLE_11A || 26808c2ecf20Sopenharmony_ci ppdu_info->preamble_type == HAL_RX_PREAMBLE_11B) { 26818c2ecf20Sopenharmony_ci ppdu_info->nss = 1; 26828c2ecf20Sopenharmony_ci ppdu_info->mcs = HAL_RX_MAX_MCS; 26838c2ecf20Sopenharmony_ci ppdu_info->tid = IEEE80211_NUM_TIDS; 26848c2ecf20Sopenharmony_ci } 26858c2ecf20Sopenharmony_ci 26868c2ecf20Sopenharmony_ci if (ppdu_info->nss > 0 && ppdu_info->nss <= HAL_RX_MAX_NSS) 26878c2ecf20Sopenharmony_ci rx_stats->nss_count[ppdu_info->nss - 1] += num_msdu; 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_ci if (ppdu_info->mcs <= HAL_RX_MAX_MCS) 26908c2ecf20Sopenharmony_ci rx_stats->mcs_count[ppdu_info->mcs] += num_msdu; 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ci if (ppdu_info->gi < HAL_RX_GI_MAX) 26938c2ecf20Sopenharmony_ci rx_stats->gi_count[ppdu_info->gi] += num_msdu; 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci if (ppdu_info->bw < HAL_RX_BW_MAX) 26968c2ecf20Sopenharmony_ci rx_stats->bw_count[ppdu_info->bw] += num_msdu; 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_ci if (ppdu_info->ldpc < HAL_RX_SU_MU_CODING_MAX) 26998c2ecf20Sopenharmony_ci rx_stats->coding_count[ppdu_info->ldpc] += num_msdu; 27008c2ecf20Sopenharmony_ci 27018c2ecf20Sopenharmony_ci if (ppdu_info->tid <= IEEE80211_NUM_TIDS) 27028c2ecf20Sopenharmony_ci rx_stats->tid_count[ppdu_info->tid] += num_msdu; 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_ci if (ppdu_info->preamble_type < HAL_RX_PREAMBLE_MAX) 27058c2ecf20Sopenharmony_ci rx_stats->pream_cnt[ppdu_info->preamble_type] += num_msdu; 27068c2ecf20Sopenharmony_ci 27078c2ecf20Sopenharmony_ci if (ppdu_info->reception_type < HAL_RX_RECEPTION_TYPE_MAX) 27088c2ecf20Sopenharmony_ci rx_stats->reception_type[ppdu_info->reception_type] += num_msdu; 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci if (ppdu_info->is_stbc) 27118c2ecf20Sopenharmony_ci rx_stats->stbc_count += num_msdu; 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci if (ppdu_info->beamformed) 27148c2ecf20Sopenharmony_ci rx_stats->beamformed_count += num_msdu; 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_ci if (ppdu_info->num_mpdu_fcs_ok > 1) 27178c2ecf20Sopenharmony_ci rx_stats->ampdu_msdu_count += num_msdu; 27188c2ecf20Sopenharmony_ci else 27198c2ecf20Sopenharmony_ci rx_stats->non_ampdu_msdu_count += num_msdu; 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_ci rx_stats->num_mpdu_fcs_ok += ppdu_info->num_mpdu_fcs_ok; 27228c2ecf20Sopenharmony_ci rx_stats->num_mpdu_fcs_err += ppdu_info->num_mpdu_fcs_err; 27238c2ecf20Sopenharmony_ci rx_stats->dcm_count += ppdu_info->dcm; 27248c2ecf20Sopenharmony_ci rx_stats->ru_alloc_cnt[ppdu_info->ru_alloc] += num_msdu; 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_ci arsta->rssi_comb = ppdu_info->rssi_comb; 27278c2ecf20Sopenharmony_ci rx_stats->rx_duration += ppdu_info->rx_duration; 27288c2ecf20Sopenharmony_ci arsta->rx_duration = rx_stats->rx_duration; 27298c2ecf20Sopenharmony_ci} 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_cistatic struct sk_buff *ath11k_dp_rx_alloc_mon_status_buf(struct ath11k_base *ab, 27328c2ecf20Sopenharmony_ci struct dp_rxdma_ring *rx_ring, 27338c2ecf20Sopenharmony_ci int *buf_id) 27348c2ecf20Sopenharmony_ci{ 27358c2ecf20Sopenharmony_ci struct sk_buff *skb; 27368c2ecf20Sopenharmony_ci dma_addr_t paddr; 27378c2ecf20Sopenharmony_ci 27388c2ecf20Sopenharmony_ci skb = dev_alloc_skb(DP_RX_BUFFER_SIZE + 27398c2ecf20Sopenharmony_ci DP_RX_BUFFER_ALIGN_SIZE); 27408c2ecf20Sopenharmony_ci 27418c2ecf20Sopenharmony_ci if (!skb) 27428c2ecf20Sopenharmony_ci goto fail_alloc_skb; 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci if (!IS_ALIGNED((unsigned long)skb->data, 27458c2ecf20Sopenharmony_ci DP_RX_BUFFER_ALIGN_SIZE)) { 27468c2ecf20Sopenharmony_ci skb_pull(skb, PTR_ALIGN(skb->data, DP_RX_BUFFER_ALIGN_SIZE) - 27478c2ecf20Sopenharmony_ci skb->data); 27488c2ecf20Sopenharmony_ci } 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_ci paddr = dma_map_single(ab->dev, skb->data, 27518c2ecf20Sopenharmony_ci skb->len + skb_tailroom(skb), 27528c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 27538c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(ab->dev, paddr))) 27548c2ecf20Sopenharmony_ci goto fail_free_skb; 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci spin_lock_bh(&rx_ring->idr_lock); 27578c2ecf20Sopenharmony_ci *buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 0, 27588c2ecf20Sopenharmony_ci rx_ring->bufs_max, GFP_ATOMIC); 27598c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 27608c2ecf20Sopenharmony_ci if (*buf_id < 0) 27618c2ecf20Sopenharmony_ci goto fail_dma_unmap; 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci ATH11K_SKB_RXCB(skb)->paddr = paddr; 27648c2ecf20Sopenharmony_ci return skb; 27658c2ecf20Sopenharmony_ci 27668c2ecf20Sopenharmony_cifail_dma_unmap: 27678c2ecf20Sopenharmony_ci dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb), 27688c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 27698c2ecf20Sopenharmony_cifail_free_skb: 27708c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 27718c2ecf20Sopenharmony_cifail_alloc_skb: 27728c2ecf20Sopenharmony_ci return NULL; 27738c2ecf20Sopenharmony_ci} 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ciint ath11k_dp_rx_mon_status_bufs_replenish(struct ath11k_base *ab, int mac_id, 27768c2ecf20Sopenharmony_ci struct dp_rxdma_ring *rx_ring, 27778c2ecf20Sopenharmony_ci int req_entries, 27788c2ecf20Sopenharmony_ci enum hal_rx_buf_return_buf_manager mgr) 27798c2ecf20Sopenharmony_ci{ 27808c2ecf20Sopenharmony_ci struct hal_srng *srng; 27818c2ecf20Sopenharmony_ci u32 *desc; 27828c2ecf20Sopenharmony_ci struct sk_buff *skb; 27838c2ecf20Sopenharmony_ci int num_free; 27848c2ecf20Sopenharmony_ci int num_remain; 27858c2ecf20Sopenharmony_ci int buf_id; 27868c2ecf20Sopenharmony_ci u32 cookie; 27878c2ecf20Sopenharmony_ci dma_addr_t paddr; 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci req_entries = min(req_entries, rx_ring->bufs_max); 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci srng = &ab->hal.srng_list[rx_ring->refill_buf_ring.ring_id]; 27928c2ecf20Sopenharmony_ci 27938c2ecf20Sopenharmony_ci spin_lock_bh(&srng->lock); 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci ath11k_hal_srng_access_begin(ab, srng); 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci num_free = ath11k_hal_srng_src_num_free(ab, srng, true); 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ci req_entries = min(num_free, req_entries); 28008c2ecf20Sopenharmony_ci num_remain = req_entries; 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci while (num_remain > 0) { 28038c2ecf20Sopenharmony_ci skb = ath11k_dp_rx_alloc_mon_status_buf(ab, rx_ring, 28048c2ecf20Sopenharmony_ci &buf_id); 28058c2ecf20Sopenharmony_ci if (!skb) 28068c2ecf20Sopenharmony_ci break; 28078c2ecf20Sopenharmony_ci paddr = ATH11K_SKB_RXCB(skb)->paddr; 28088c2ecf20Sopenharmony_ci 28098c2ecf20Sopenharmony_ci desc = ath11k_hal_srng_src_get_next_entry(ab, srng); 28108c2ecf20Sopenharmony_ci if (!desc) 28118c2ecf20Sopenharmony_ci goto fail_desc_get; 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_ci cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, mac_id) | 28148c2ecf20Sopenharmony_ci FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id); 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_ci num_remain--; 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_ci ath11k_hal_rx_buf_addr_info_set(desc, paddr, cookie, mgr); 28198c2ecf20Sopenharmony_ci } 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_ci spin_unlock_bh(&srng->lock); 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ci return req_entries - num_remain; 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_cifail_desc_get: 28288c2ecf20Sopenharmony_ci spin_lock_bh(&rx_ring->idr_lock); 28298c2ecf20Sopenharmony_ci idr_remove(&rx_ring->bufs_idr, buf_id); 28308c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 28318c2ecf20Sopenharmony_ci dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb), 28328c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 28338c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 28348c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 28358c2ecf20Sopenharmony_ci spin_unlock_bh(&srng->lock); 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_ci return req_entries - num_remain; 28388c2ecf20Sopenharmony_ci} 28398c2ecf20Sopenharmony_ci 28408c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, 28418c2ecf20Sopenharmony_ci int *budget, struct sk_buff_head *skb_list) 28428c2ecf20Sopenharmony_ci{ 28438c2ecf20Sopenharmony_ci struct ath11k *ar; 28448c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp; 28458c2ecf20Sopenharmony_ci struct dp_rxdma_ring *rx_ring; 28468c2ecf20Sopenharmony_ci struct hal_srng *srng; 28478c2ecf20Sopenharmony_ci void *rx_mon_status_desc; 28488c2ecf20Sopenharmony_ci struct sk_buff *skb; 28498c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb; 28508c2ecf20Sopenharmony_ci struct hal_tlv_hdr *tlv; 28518c2ecf20Sopenharmony_ci u32 cookie; 28528c2ecf20Sopenharmony_ci int buf_id, srng_id; 28538c2ecf20Sopenharmony_ci dma_addr_t paddr; 28548c2ecf20Sopenharmony_ci u8 rbm; 28558c2ecf20Sopenharmony_ci int num_buffs_reaped = 0; 28568c2ecf20Sopenharmony_ci 28578c2ecf20Sopenharmony_ci ar = ab->pdevs[ath11k_hw_mac_id_to_pdev_id(&ab->hw_params, mac_id)].ar; 28588c2ecf20Sopenharmony_ci dp = &ar->dp; 28598c2ecf20Sopenharmony_ci srng_id = ath11k_hw_mac_id_to_srng_id(&ab->hw_params, mac_id); 28608c2ecf20Sopenharmony_ci rx_ring = &dp->rx_mon_status_refill_ring[srng_id]; 28618c2ecf20Sopenharmony_ci 28628c2ecf20Sopenharmony_ci srng = &ab->hal.srng_list[rx_ring->refill_buf_ring.ring_id]; 28638c2ecf20Sopenharmony_ci 28648c2ecf20Sopenharmony_ci spin_lock_bh(&srng->lock); 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci ath11k_hal_srng_access_begin(ab, srng); 28678c2ecf20Sopenharmony_ci while (*budget) { 28688c2ecf20Sopenharmony_ci *budget -= 1; 28698c2ecf20Sopenharmony_ci rx_mon_status_desc = 28708c2ecf20Sopenharmony_ci ath11k_hal_srng_src_peek(ab, srng); 28718c2ecf20Sopenharmony_ci if (!rx_mon_status_desc) 28728c2ecf20Sopenharmony_ci break; 28738c2ecf20Sopenharmony_ci 28748c2ecf20Sopenharmony_ci ath11k_hal_rx_buf_addr_info_get(rx_mon_status_desc, &paddr, 28758c2ecf20Sopenharmony_ci &cookie, &rbm); 28768c2ecf20Sopenharmony_ci if (paddr) { 28778c2ecf20Sopenharmony_ci buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, cookie); 28788c2ecf20Sopenharmony_ci 28798c2ecf20Sopenharmony_ci spin_lock_bh(&rx_ring->idr_lock); 28808c2ecf20Sopenharmony_ci skb = idr_find(&rx_ring->bufs_idr, buf_id); 28818c2ecf20Sopenharmony_ci if (!skb) { 28828c2ecf20Sopenharmony_ci ath11k_warn(ab, "rx monitor status with invalid buf_id %d\n", 28838c2ecf20Sopenharmony_ci buf_id); 28848c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 28858c2ecf20Sopenharmony_ci goto move_next; 28868c2ecf20Sopenharmony_ci } 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_ci idr_remove(&rx_ring->bufs_idr, buf_id); 28898c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_ci rxcb = ATH11K_SKB_RXCB(skb); 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(ab->dev, rxcb->paddr, 28948c2ecf20Sopenharmony_ci skb->len + skb_tailroom(skb), 28958c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_ci dma_unmap_single(ab->dev, rxcb->paddr, 28988c2ecf20Sopenharmony_ci skb->len + skb_tailroom(skb), 28998c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 29008c2ecf20Sopenharmony_ci 29018c2ecf20Sopenharmony_ci tlv = (struct hal_tlv_hdr *)skb->data; 29028c2ecf20Sopenharmony_ci if (FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl) != 29038c2ecf20Sopenharmony_ci HAL_RX_STATUS_BUFFER_DONE) { 29048c2ecf20Sopenharmony_ci ath11k_warn(ab, "mon status DONE not set %lx\n", 29058c2ecf20Sopenharmony_ci FIELD_GET(HAL_TLV_HDR_TAG, 29068c2ecf20Sopenharmony_ci tlv->tl)); 29078c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 29088c2ecf20Sopenharmony_ci goto move_next; 29098c2ecf20Sopenharmony_ci } 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci __skb_queue_tail(skb_list, skb); 29128c2ecf20Sopenharmony_ci } 29138c2ecf20Sopenharmony_cimove_next: 29148c2ecf20Sopenharmony_ci skb = ath11k_dp_rx_alloc_mon_status_buf(ab, rx_ring, 29158c2ecf20Sopenharmony_ci &buf_id); 29168c2ecf20Sopenharmony_ci 29178c2ecf20Sopenharmony_ci if (!skb) { 29188c2ecf20Sopenharmony_ci ath11k_hal_rx_buf_addr_info_set(rx_mon_status_desc, 0, 0, 29198c2ecf20Sopenharmony_ci HAL_RX_BUF_RBM_SW3_BM); 29208c2ecf20Sopenharmony_ci num_buffs_reaped++; 29218c2ecf20Sopenharmony_ci break; 29228c2ecf20Sopenharmony_ci } 29238c2ecf20Sopenharmony_ci rxcb = ATH11K_SKB_RXCB(skb); 29248c2ecf20Sopenharmony_ci 29258c2ecf20Sopenharmony_ci cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, mac_id) | 29268c2ecf20Sopenharmony_ci FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id); 29278c2ecf20Sopenharmony_ci 29288c2ecf20Sopenharmony_ci ath11k_hal_rx_buf_addr_info_set(rx_mon_status_desc, rxcb->paddr, 29298c2ecf20Sopenharmony_ci cookie, HAL_RX_BUF_RBM_SW3_BM); 29308c2ecf20Sopenharmony_ci ath11k_hal_srng_src_get_next_entry(ab, srng); 29318c2ecf20Sopenharmony_ci num_buffs_reaped++; 29328c2ecf20Sopenharmony_ci } 29338c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 29348c2ecf20Sopenharmony_ci spin_unlock_bh(&srng->lock); 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci return num_buffs_reaped; 29378c2ecf20Sopenharmony_ci} 29388c2ecf20Sopenharmony_ci 29398c2ecf20Sopenharmony_ciint ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id, 29408c2ecf20Sopenharmony_ci struct napi_struct *napi, int budget) 29418c2ecf20Sopenharmony_ci{ 29428c2ecf20Sopenharmony_ci struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); 29438c2ecf20Sopenharmony_ci enum hal_rx_mon_status hal_status; 29448c2ecf20Sopenharmony_ci struct sk_buff *skb; 29458c2ecf20Sopenharmony_ci struct sk_buff_head skb_list; 29468c2ecf20Sopenharmony_ci struct hal_rx_mon_ppdu_info ppdu_info; 29478c2ecf20Sopenharmony_ci struct ath11k_peer *peer; 29488c2ecf20Sopenharmony_ci struct ath11k_sta *arsta; 29498c2ecf20Sopenharmony_ci int num_buffs_reaped = 0; 29508c2ecf20Sopenharmony_ci 29518c2ecf20Sopenharmony_ci __skb_queue_head_init(&skb_list); 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci num_buffs_reaped = ath11k_dp_rx_reap_mon_status_ring(ab, mac_id, &budget, 29548c2ecf20Sopenharmony_ci &skb_list); 29558c2ecf20Sopenharmony_ci if (!num_buffs_reaped) 29568c2ecf20Sopenharmony_ci goto exit; 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&skb_list))) { 29598c2ecf20Sopenharmony_ci memset(&ppdu_info, 0, sizeof(ppdu_info)); 29608c2ecf20Sopenharmony_ci ppdu_info.peer_id = HAL_INVALID_PEERID; 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_ci if (ath11k_debugfs_is_pktlog_rx_stats_enabled(ar)) 29638c2ecf20Sopenharmony_ci trace_ath11k_htt_rxdesc(ar, skb->data, DP_RX_BUFFER_SIZE); 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci hal_status = ath11k_hal_rx_parse_mon_status(ab, &ppdu_info, skb); 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci if (ppdu_info.peer_id == HAL_INVALID_PEERID || 29688c2ecf20Sopenharmony_ci hal_status != HAL_RX_MON_STATUS_PPDU_DONE) { 29698c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 29708c2ecf20Sopenharmony_ci continue; 29718c2ecf20Sopenharmony_ci } 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci rcu_read_lock(); 29748c2ecf20Sopenharmony_ci spin_lock_bh(&ab->base_lock); 29758c2ecf20Sopenharmony_ci peer = ath11k_peer_find_by_id(ab, ppdu_info.peer_id); 29768c2ecf20Sopenharmony_ci 29778c2ecf20Sopenharmony_ci if (!peer || !peer->sta) { 29788c2ecf20Sopenharmony_ci ath11k_dbg(ab, ATH11K_DBG_DATA, 29798c2ecf20Sopenharmony_ci "failed to find the peer with peer_id %d\n", 29808c2ecf20Sopenharmony_ci ppdu_info.peer_id); 29818c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 29828c2ecf20Sopenharmony_ci rcu_read_unlock(); 29838c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 29848c2ecf20Sopenharmony_ci continue; 29858c2ecf20Sopenharmony_ci } 29868c2ecf20Sopenharmony_ci 29878c2ecf20Sopenharmony_ci arsta = (struct ath11k_sta *)peer->sta->drv_priv; 29888c2ecf20Sopenharmony_ci ath11k_dp_rx_update_peer_stats(arsta, &ppdu_info); 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_ci if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr)) 29918c2ecf20Sopenharmony_ci trace_ath11k_htt_rxdesc(ar, skb->data, DP_RX_BUFFER_SIZE); 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 29948c2ecf20Sopenharmony_ci rcu_read_unlock(); 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 29978c2ecf20Sopenharmony_ci } 29988c2ecf20Sopenharmony_ciexit: 29998c2ecf20Sopenharmony_ci return num_buffs_reaped; 30008c2ecf20Sopenharmony_ci} 30018c2ecf20Sopenharmony_ci 30028c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_frag_timer(struct timer_list *timer) 30038c2ecf20Sopenharmony_ci{ 30048c2ecf20Sopenharmony_ci struct dp_rx_tid *rx_tid = from_timer(rx_tid, timer, frag_timer); 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_ci spin_lock_bh(&rx_tid->ab->base_lock); 30078c2ecf20Sopenharmony_ci if (rx_tid->last_frag_no && 30088c2ecf20Sopenharmony_ci rx_tid->rx_frag_bitmap == GENMASK(rx_tid->last_frag_no, 0)) { 30098c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_tid->ab->base_lock); 30108c2ecf20Sopenharmony_ci return; 30118c2ecf20Sopenharmony_ci } 30128c2ecf20Sopenharmony_ci ath11k_dp_rx_frags_cleanup(rx_tid, true); 30138c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_tid->ab->base_lock); 30148c2ecf20Sopenharmony_ci} 30158c2ecf20Sopenharmony_ci 30168c2ecf20Sopenharmony_ciint ath11k_peer_rx_frag_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id) 30178c2ecf20Sopenharmony_ci{ 30188c2ecf20Sopenharmony_ci struct ath11k_base *ab = ar->ab; 30198c2ecf20Sopenharmony_ci struct crypto_shash *tfm; 30208c2ecf20Sopenharmony_ci struct ath11k_peer *peer; 30218c2ecf20Sopenharmony_ci struct dp_rx_tid *rx_tid; 30228c2ecf20Sopenharmony_ci int i; 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_ci tfm = crypto_alloc_shash("michael_mic", 0, 0); 30258c2ecf20Sopenharmony_ci if (IS_ERR(tfm)) 30268c2ecf20Sopenharmony_ci return PTR_ERR(tfm); 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci spin_lock_bh(&ab->base_lock); 30298c2ecf20Sopenharmony_ci 30308c2ecf20Sopenharmony_ci peer = ath11k_peer_find(ab, vdev_id, peer_mac); 30318c2ecf20Sopenharmony_ci if (!peer) { 30328c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to find the peer to set up fragment info\n"); 30338c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 30348c2ecf20Sopenharmony_ci crypto_free_shash(tfm); 30358c2ecf20Sopenharmony_ci return -ENOENT; 30368c2ecf20Sopenharmony_ci } 30378c2ecf20Sopenharmony_ci 30388c2ecf20Sopenharmony_ci for (i = 0; i <= IEEE80211_NUM_TIDS; i++) { 30398c2ecf20Sopenharmony_ci rx_tid = &peer->rx_tid[i]; 30408c2ecf20Sopenharmony_ci rx_tid->ab = ab; 30418c2ecf20Sopenharmony_ci timer_setup(&rx_tid->frag_timer, ath11k_dp_rx_frag_timer, 0); 30428c2ecf20Sopenharmony_ci skb_queue_head_init(&rx_tid->rx_frags); 30438c2ecf20Sopenharmony_ci } 30448c2ecf20Sopenharmony_ci 30458c2ecf20Sopenharmony_ci peer->tfm_mmic = tfm; 30468c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci return 0; 30498c2ecf20Sopenharmony_ci} 30508c2ecf20Sopenharmony_ci 30518c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_h_michael_mic(struct crypto_shash *tfm, u8 *key, 30528c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr, u8 *data, 30538c2ecf20Sopenharmony_ci size_t data_len, u8 *mic) 30548c2ecf20Sopenharmony_ci{ 30558c2ecf20Sopenharmony_ci SHASH_DESC_ON_STACK(desc, tfm); 30568c2ecf20Sopenharmony_ci u8 mic_hdr[16] = {0}; 30578c2ecf20Sopenharmony_ci u8 tid = 0; 30588c2ecf20Sopenharmony_ci int ret; 30598c2ecf20Sopenharmony_ci 30608c2ecf20Sopenharmony_ci if (!tfm) 30618c2ecf20Sopenharmony_ci return -EINVAL; 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_ci desc->tfm = tfm; 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_ci ret = crypto_shash_setkey(tfm, key, 8); 30668c2ecf20Sopenharmony_ci if (ret) 30678c2ecf20Sopenharmony_ci goto out; 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci ret = crypto_shash_init(desc); 30708c2ecf20Sopenharmony_ci if (ret) 30718c2ecf20Sopenharmony_ci goto out; 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci /* TKIP MIC header */ 30748c2ecf20Sopenharmony_ci memcpy(mic_hdr, ieee80211_get_DA(hdr), ETH_ALEN); 30758c2ecf20Sopenharmony_ci memcpy(mic_hdr + ETH_ALEN, ieee80211_get_SA(hdr), ETH_ALEN); 30768c2ecf20Sopenharmony_ci if (ieee80211_is_data_qos(hdr->frame_control)) 30778c2ecf20Sopenharmony_ci tid = ieee80211_get_tid(hdr); 30788c2ecf20Sopenharmony_ci mic_hdr[12] = tid; 30798c2ecf20Sopenharmony_ci 30808c2ecf20Sopenharmony_ci ret = crypto_shash_update(desc, mic_hdr, 16); 30818c2ecf20Sopenharmony_ci if (ret) 30828c2ecf20Sopenharmony_ci goto out; 30838c2ecf20Sopenharmony_ci ret = crypto_shash_update(desc, data, data_len); 30848c2ecf20Sopenharmony_ci if (ret) 30858c2ecf20Sopenharmony_ci goto out; 30868c2ecf20Sopenharmony_ci ret = crypto_shash_final(desc, mic); 30878c2ecf20Sopenharmony_ciout: 30888c2ecf20Sopenharmony_ci shash_desc_zero(desc); 30898c2ecf20Sopenharmony_ci return ret; 30908c2ecf20Sopenharmony_ci} 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_h_verify_tkip_mic(struct ath11k *ar, struct ath11k_peer *peer, 30938c2ecf20Sopenharmony_ci struct sk_buff *msdu) 30948c2ecf20Sopenharmony_ci{ 30958c2ecf20Sopenharmony_ci struct hal_rx_desc *rx_desc = (struct hal_rx_desc *)msdu->data; 30968c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rxs = IEEE80211_SKB_RXCB(msdu); 30978c2ecf20Sopenharmony_ci struct ieee80211_key_conf *key_conf; 30988c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 30998c2ecf20Sopenharmony_ci u8 mic[IEEE80211_CCMP_MIC_LEN]; 31008c2ecf20Sopenharmony_ci int head_len, tail_len, ret; 31018c2ecf20Sopenharmony_ci size_t data_len; 31028c2ecf20Sopenharmony_ci u32 hdr_len; 31038c2ecf20Sopenharmony_ci u8 *key, *data; 31048c2ecf20Sopenharmony_ci u8 key_idx; 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci if (ath11k_dp_rx_h_mpdu_start_enctype(rx_desc) != HAL_ENCRYPT_TYPE_TKIP_MIC) 31078c2ecf20Sopenharmony_ci return 0; 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)(msdu->data + HAL_RX_DESC_SIZE); 31108c2ecf20Sopenharmony_ci hdr_len = ieee80211_hdrlen(hdr->frame_control); 31118c2ecf20Sopenharmony_ci head_len = hdr_len + HAL_RX_DESC_SIZE + IEEE80211_TKIP_IV_LEN; 31128c2ecf20Sopenharmony_ci tail_len = IEEE80211_CCMP_MIC_LEN + IEEE80211_TKIP_ICV_LEN + FCS_LEN; 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_ci if (!is_multicast_ether_addr(hdr->addr1)) 31158c2ecf20Sopenharmony_ci key_idx = peer->ucast_keyidx; 31168c2ecf20Sopenharmony_ci else 31178c2ecf20Sopenharmony_ci key_idx = peer->mcast_keyidx; 31188c2ecf20Sopenharmony_ci 31198c2ecf20Sopenharmony_ci key_conf = peer->keys[key_idx]; 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ci data = msdu->data + head_len; 31228c2ecf20Sopenharmony_ci data_len = msdu->len - head_len - tail_len; 31238c2ecf20Sopenharmony_ci key = &key_conf->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]; 31248c2ecf20Sopenharmony_ci 31258c2ecf20Sopenharmony_ci ret = ath11k_dp_rx_h_michael_mic(peer->tfm_mmic, key, hdr, data, data_len, mic); 31268c2ecf20Sopenharmony_ci if (ret || memcmp(mic, data + data_len, IEEE80211_CCMP_MIC_LEN)) 31278c2ecf20Sopenharmony_ci goto mic_fail; 31288c2ecf20Sopenharmony_ci 31298c2ecf20Sopenharmony_ci return 0; 31308c2ecf20Sopenharmony_ci 31318c2ecf20Sopenharmony_cimic_fail: 31328c2ecf20Sopenharmony_ci (ATH11K_SKB_RXCB(msdu))->is_first_msdu = true; 31338c2ecf20Sopenharmony_ci (ATH11K_SKB_RXCB(msdu))->is_last_msdu = true; 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_ci rxs->flag |= RX_FLAG_MMIC_ERROR | RX_FLAG_MMIC_STRIPPED | 31368c2ecf20Sopenharmony_ci RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED; 31378c2ecf20Sopenharmony_ci skb_pull(msdu, HAL_RX_DESC_SIZE); 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci ath11k_dp_rx_h_ppdu(ar, rx_desc, rxs); 31408c2ecf20Sopenharmony_ci ath11k_dp_rx_h_undecap(ar, msdu, rx_desc, 31418c2ecf20Sopenharmony_ci HAL_ENCRYPT_TYPE_TKIP_MIC, rxs, true); 31428c2ecf20Sopenharmony_ci ieee80211_rx(ar->hw, msdu); 31438c2ecf20Sopenharmony_ci return -EINVAL; 31448c2ecf20Sopenharmony_ci} 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_undecap_frag(struct ath11k *ar, struct sk_buff *msdu, 31478c2ecf20Sopenharmony_ci enum hal_encrypt_type enctype, u32 flags) 31488c2ecf20Sopenharmony_ci{ 31498c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 31508c2ecf20Sopenharmony_ci size_t hdr_len; 31518c2ecf20Sopenharmony_ci size_t crypto_len; 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_ci if (!flags) 31548c2ecf20Sopenharmony_ci return; 31558c2ecf20Sopenharmony_ci 31568c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)(msdu->data + HAL_RX_DESC_SIZE); 31578c2ecf20Sopenharmony_ci 31588c2ecf20Sopenharmony_ci if (flags & RX_FLAG_MIC_STRIPPED) 31598c2ecf20Sopenharmony_ci skb_trim(msdu, msdu->len - 31608c2ecf20Sopenharmony_ci ath11k_dp_rx_crypto_mic_len(ar, enctype)); 31618c2ecf20Sopenharmony_ci 31628c2ecf20Sopenharmony_ci if (flags & RX_FLAG_ICV_STRIPPED) 31638c2ecf20Sopenharmony_ci skb_trim(msdu, msdu->len - 31648c2ecf20Sopenharmony_ci ath11k_dp_rx_crypto_icv_len(ar, enctype)); 31658c2ecf20Sopenharmony_ci 31668c2ecf20Sopenharmony_ci if (flags & RX_FLAG_IV_STRIPPED) { 31678c2ecf20Sopenharmony_ci hdr_len = ieee80211_hdrlen(hdr->frame_control); 31688c2ecf20Sopenharmony_ci crypto_len = ath11k_dp_rx_crypto_param_len(ar, enctype); 31698c2ecf20Sopenharmony_ci 31708c2ecf20Sopenharmony_ci memmove((void *)msdu->data + HAL_RX_DESC_SIZE + crypto_len, 31718c2ecf20Sopenharmony_ci (void *)msdu->data + HAL_RX_DESC_SIZE, hdr_len); 31728c2ecf20Sopenharmony_ci skb_pull(msdu, crypto_len); 31738c2ecf20Sopenharmony_ci } 31748c2ecf20Sopenharmony_ci} 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_h_defrag(struct ath11k *ar, 31778c2ecf20Sopenharmony_ci struct ath11k_peer *peer, 31788c2ecf20Sopenharmony_ci struct dp_rx_tid *rx_tid, 31798c2ecf20Sopenharmony_ci struct sk_buff **defrag_skb) 31808c2ecf20Sopenharmony_ci{ 31818c2ecf20Sopenharmony_ci struct hal_rx_desc *rx_desc; 31828c2ecf20Sopenharmony_ci struct sk_buff *skb, *first_frag, *last_frag; 31838c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 31848c2ecf20Sopenharmony_ci enum hal_encrypt_type enctype; 31858c2ecf20Sopenharmony_ci bool is_decrypted = false; 31868c2ecf20Sopenharmony_ci int msdu_len = 0; 31878c2ecf20Sopenharmony_ci int extra_space; 31888c2ecf20Sopenharmony_ci u32 flags; 31898c2ecf20Sopenharmony_ci 31908c2ecf20Sopenharmony_ci first_frag = skb_peek(&rx_tid->rx_frags); 31918c2ecf20Sopenharmony_ci last_frag = skb_peek_tail(&rx_tid->rx_frags); 31928c2ecf20Sopenharmony_ci 31938c2ecf20Sopenharmony_ci skb_queue_walk(&rx_tid->rx_frags, skb) { 31948c2ecf20Sopenharmony_ci flags = 0; 31958c2ecf20Sopenharmony_ci rx_desc = (struct hal_rx_desc *)skb->data; 31968c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)(skb->data + HAL_RX_DESC_SIZE); 31978c2ecf20Sopenharmony_ci 31988c2ecf20Sopenharmony_ci enctype = ath11k_dp_rx_h_mpdu_start_enctype(rx_desc); 31998c2ecf20Sopenharmony_ci if (enctype != HAL_ENCRYPT_TYPE_OPEN) 32008c2ecf20Sopenharmony_ci is_decrypted = ath11k_dp_rx_h_attn_is_decrypted(rx_desc); 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_ci if (is_decrypted) { 32038c2ecf20Sopenharmony_ci if (skb != first_frag) 32048c2ecf20Sopenharmony_ci flags |= RX_FLAG_IV_STRIPPED; 32058c2ecf20Sopenharmony_ci if (skb != last_frag) 32068c2ecf20Sopenharmony_ci flags |= RX_FLAG_ICV_STRIPPED | 32078c2ecf20Sopenharmony_ci RX_FLAG_MIC_STRIPPED; 32088c2ecf20Sopenharmony_ci } 32098c2ecf20Sopenharmony_ci 32108c2ecf20Sopenharmony_ci /* RX fragments are always raw packets */ 32118c2ecf20Sopenharmony_ci if (skb != last_frag) 32128c2ecf20Sopenharmony_ci skb_trim(skb, skb->len - FCS_LEN); 32138c2ecf20Sopenharmony_ci ath11k_dp_rx_h_undecap_frag(ar, skb, enctype, flags); 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci if (skb != first_frag) 32168c2ecf20Sopenharmony_ci skb_pull(skb, HAL_RX_DESC_SIZE + 32178c2ecf20Sopenharmony_ci ieee80211_hdrlen(hdr->frame_control)); 32188c2ecf20Sopenharmony_ci msdu_len += skb->len; 32198c2ecf20Sopenharmony_ci } 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_ci extra_space = msdu_len - (DP_RX_BUFFER_SIZE + skb_tailroom(first_frag)); 32228c2ecf20Sopenharmony_ci if (extra_space > 0 && 32238c2ecf20Sopenharmony_ci (pskb_expand_head(first_frag, 0, extra_space, GFP_ATOMIC) < 0)) 32248c2ecf20Sopenharmony_ci return -ENOMEM; 32258c2ecf20Sopenharmony_ci 32268c2ecf20Sopenharmony_ci __skb_unlink(first_frag, &rx_tid->rx_frags); 32278c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&rx_tid->rx_frags))) { 32288c2ecf20Sopenharmony_ci skb_put_data(first_frag, skb->data, skb->len); 32298c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 32308c2ecf20Sopenharmony_ci } 32318c2ecf20Sopenharmony_ci 32328c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)(first_frag->data + HAL_RX_DESC_SIZE); 32338c2ecf20Sopenharmony_ci hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); 32348c2ecf20Sopenharmony_ci ATH11K_SKB_RXCB(first_frag)->is_frag = 1; 32358c2ecf20Sopenharmony_ci 32368c2ecf20Sopenharmony_ci if (ath11k_dp_rx_h_verify_tkip_mic(ar, peer, first_frag)) 32378c2ecf20Sopenharmony_ci first_frag = NULL; 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_ci *defrag_skb = first_frag; 32408c2ecf20Sopenharmony_ci return 0; 32418c2ecf20Sopenharmony_ci} 32428c2ecf20Sopenharmony_ci 32438c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_h_defrag_reo_reinject(struct ath11k *ar, struct dp_rx_tid *rx_tid, 32448c2ecf20Sopenharmony_ci struct sk_buff *defrag_skb) 32458c2ecf20Sopenharmony_ci{ 32468c2ecf20Sopenharmony_ci struct ath11k_base *ab = ar->ab; 32478c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp = &ar->dp; 32488c2ecf20Sopenharmony_ci struct dp_rxdma_ring *rx_refill_ring = &dp->rx_refill_buf_ring; 32498c2ecf20Sopenharmony_ci struct hal_rx_desc *rx_desc = (struct hal_rx_desc *)defrag_skb->data; 32508c2ecf20Sopenharmony_ci struct hal_reo_entrance_ring *reo_ent_ring; 32518c2ecf20Sopenharmony_ci struct hal_reo_dest_ring *reo_dest_ring; 32528c2ecf20Sopenharmony_ci struct dp_link_desc_bank *link_desc_banks; 32538c2ecf20Sopenharmony_ci struct hal_rx_msdu_link *msdu_link; 32548c2ecf20Sopenharmony_ci struct hal_rx_msdu_details *msdu0; 32558c2ecf20Sopenharmony_ci struct hal_srng *srng; 32568c2ecf20Sopenharmony_ci dma_addr_t paddr; 32578c2ecf20Sopenharmony_ci u32 desc_bank, msdu_info, mpdu_info; 32588c2ecf20Sopenharmony_ci u32 dst_idx, cookie; 32598c2ecf20Sopenharmony_ci u32 *msdu_len_offset; 32608c2ecf20Sopenharmony_ci int ret, buf_id; 32618c2ecf20Sopenharmony_ci 32628c2ecf20Sopenharmony_ci link_desc_banks = ab->dp.link_desc_banks; 32638c2ecf20Sopenharmony_ci reo_dest_ring = rx_tid->dst_ring_desc; 32648c2ecf20Sopenharmony_ci 32658c2ecf20Sopenharmony_ci ath11k_hal_rx_reo_ent_paddr_get(ab, reo_dest_ring, &paddr, &desc_bank); 32668c2ecf20Sopenharmony_ci msdu_link = (struct hal_rx_msdu_link *)(link_desc_banks[desc_bank].vaddr + 32678c2ecf20Sopenharmony_ci (paddr - link_desc_banks[desc_bank].paddr)); 32688c2ecf20Sopenharmony_ci msdu0 = &msdu_link->msdu_link[0]; 32698c2ecf20Sopenharmony_ci dst_idx = FIELD_GET(RX_MSDU_DESC_INFO0_REO_DEST_IND, msdu0->rx_msdu_info.info0); 32708c2ecf20Sopenharmony_ci memset(msdu0, 0, sizeof(*msdu0)); 32718c2ecf20Sopenharmony_ci 32728c2ecf20Sopenharmony_ci msdu_info = FIELD_PREP(RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU, 1) | 32738c2ecf20Sopenharmony_ci FIELD_PREP(RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU, 1) | 32748c2ecf20Sopenharmony_ci FIELD_PREP(RX_MSDU_DESC_INFO0_MSDU_CONTINUATION, 0) | 32758c2ecf20Sopenharmony_ci FIELD_PREP(RX_MSDU_DESC_INFO0_MSDU_LENGTH, 32768c2ecf20Sopenharmony_ci defrag_skb->len - HAL_RX_DESC_SIZE) | 32778c2ecf20Sopenharmony_ci FIELD_PREP(RX_MSDU_DESC_INFO0_REO_DEST_IND, dst_idx) | 32788c2ecf20Sopenharmony_ci FIELD_PREP(RX_MSDU_DESC_INFO0_VALID_SA, 1) | 32798c2ecf20Sopenharmony_ci FIELD_PREP(RX_MSDU_DESC_INFO0_VALID_DA, 1); 32808c2ecf20Sopenharmony_ci msdu0->rx_msdu_info.info0 = msdu_info; 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_ci /* change msdu len in hal rx desc */ 32838c2ecf20Sopenharmony_ci msdu_len_offset = (u32 *)&rx_desc->msdu_start; 32848c2ecf20Sopenharmony_ci *msdu_len_offset &= ~(RX_MSDU_START_INFO1_MSDU_LENGTH); 32858c2ecf20Sopenharmony_ci *msdu_len_offset |= defrag_skb->len - HAL_RX_DESC_SIZE; 32868c2ecf20Sopenharmony_ci 32878c2ecf20Sopenharmony_ci paddr = dma_map_single(ab->dev, defrag_skb->data, 32888c2ecf20Sopenharmony_ci defrag_skb->len + skb_tailroom(defrag_skb), 32898c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 32908c2ecf20Sopenharmony_ci if (dma_mapping_error(ab->dev, paddr)) 32918c2ecf20Sopenharmony_ci return -ENOMEM; 32928c2ecf20Sopenharmony_ci 32938c2ecf20Sopenharmony_ci spin_lock_bh(&rx_refill_ring->idr_lock); 32948c2ecf20Sopenharmony_ci buf_id = idr_alloc(&rx_refill_ring->bufs_idr, defrag_skb, 0, 32958c2ecf20Sopenharmony_ci rx_refill_ring->bufs_max * 3, GFP_ATOMIC); 32968c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_refill_ring->idr_lock); 32978c2ecf20Sopenharmony_ci if (buf_id < 0) { 32988c2ecf20Sopenharmony_ci ret = -ENOMEM; 32998c2ecf20Sopenharmony_ci goto err_unmap_dma; 33008c2ecf20Sopenharmony_ci } 33018c2ecf20Sopenharmony_ci 33028c2ecf20Sopenharmony_ci ATH11K_SKB_RXCB(defrag_skb)->paddr = paddr; 33038c2ecf20Sopenharmony_ci cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, dp->mac_id) | 33048c2ecf20Sopenharmony_ci FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id); 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_ci ath11k_hal_rx_buf_addr_info_set(msdu0, paddr, cookie, HAL_RX_BUF_RBM_SW3_BM); 33078c2ecf20Sopenharmony_ci 33088c2ecf20Sopenharmony_ci /* Fill mpdu details into reo entrace ring */ 33098c2ecf20Sopenharmony_ci srng = &ab->hal.srng_list[ab->dp.reo_reinject_ring.ring_id]; 33108c2ecf20Sopenharmony_ci 33118c2ecf20Sopenharmony_ci spin_lock_bh(&srng->lock); 33128c2ecf20Sopenharmony_ci ath11k_hal_srng_access_begin(ab, srng); 33138c2ecf20Sopenharmony_ci 33148c2ecf20Sopenharmony_ci reo_ent_ring = (struct hal_reo_entrance_ring *) 33158c2ecf20Sopenharmony_ci ath11k_hal_srng_src_get_next_entry(ab, srng); 33168c2ecf20Sopenharmony_ci if (!reo_ent_ring) { 33178c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 33188c2ecf20Sopenharmony_ci spin_unlock_bh(&srng->lock); 33198c2ecf20Sopenharmony_ci ret = -ENOSPC; 33208c2ecf20Sopenharmony_ci goto err_free_idr; 33218c2ecf20Sopenharmony_ci } 33228c2ecf20Sopenharmony_ci memset(reo_ent_ring, 0, sizeof(*reo_ent_ring)); 33238c2ecf20Sopenharmony_ci 33248c2ecf20Sopenharmony_ci ath11k_hal_rx_reo_ent_paddr_get(ab, reo_dest_ring, &paddr, &desc_bank); 33258c2ecf20Sopenharmony_ci ath11k_hal_rx_buf_addr_info_set(reo_ent_ring, paddr, desc_bank, 33268c2ecf20Sopenharmony_ci HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST); 33278c2ecf20Sopenharmony_ci 33288c2ecf20Sopenharmony_ci mpdu_info = FIELD_PREP(RX_MPDU_DESC_INFO0_MSDU_COUNT, 1) | 33298c2ecf20Sopenharmony_ci FIELD_PREP(RX_MPDU_DESC_INFO0_SEQ_NUM, rx_tid->cur_sn) | 33308c2ecf20Sopenharmony_ci FIELD_PREP(RX_MPDU_DESC_INFO0_FRAG_FLAG, 0) | 33318c2ecf20Sopenharmony_ci FIELD_PREP(RX_MPDU_DESC_INFO0_VALID_SA, 1) | 33328c2ecf20Sopenharmony_ci FIELD_PREP(RX_MPDU_DESC_INFO0_VALID_DA, 1) | 33338c2ecf20Sopenharmony_ci FIELD_PREP(RX_MPDU_DESC_INFO0_RAW_MPDU, 1) | 33348c2ecf20Sopenharmony_ci FIELD_PREP(RX_MPDU_DESC_INFO0_VALID_PN, 1); 33358c2ecf20Sopenharmony_ci 33368c2ecf20Sopenharmony_ci reo_ent_ring->rx_mpdu_info.info0 = mpdu_info; 33378c2ecf20Sopenharmony_ci reo_ent_ring->rx_mpdu_info.meta_data = reo_dest_ring->rx_mpdu_info.meta_data; 33388c2ecf20Sopenharmony_ci reo_ent_ring->queue_addr_lo = reo_dest_ring->queue_addr_lo; 33398c2ecf20Sopenharmony_ci reo_ent_ring->info0 = FIELD_PREP(HAL_REO_ENTR_RING_INFO0_QUEUE_ADDR_HI, 33408c2ecf20Sopenharmony_ci FIELD_GET(HAL_REO_DEST_RING_INFO0_QUEUE_ADDR_HI, 33418c2ecf20Sopenharmony_ci reo_dest_ring->info0)) | 33428c2ecf20Sopenharmony_ci FIELD_PREP(HAL_REO_ENTR_RING_INFO0_DEST_IND, dst_idx); 33438c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 33448c2ecf20Sopenharmony_ci spin_unlock_bh(&srng->lock); 33458c2ecf20Sopenharmony_ci 33468c2ecf20Sopenharmony_ci return 0; 33478c2ecf20Sopenharmony_ci 33488c2ecf20Sopenharmony_cierr_free_idr: 33498c2ecf20Sopenharmony_ci spin_lock_bh(&rx_refill_ring->idr_lock); 33508c2ecf20Sopenharmony_ci idr_remove(&rx_refill_ring->bufs_idr, buf_id); 33518c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_refill_ring->idr_lock); 33528c2ecf20Sopenharmony_cierr_unmap_dma: 33538c2ecf20Sopenharmony_ci dma_unmap_single(ab->dev, paddr, defrag_skb->len + skb_tailroom(defrag_skb), 33548c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 33558c2ecf20Sopenharmony_ci return ret; 33568c2ecf20Sopenharmony_ci} 33578c2ecf20Sopenharmony_ci 33588c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_h_cmp_frags(struct sk_buff *a, struct sk_buff *b) 33598c2ecf20Sopenharmony_ci{ 33608c2ecf20Sopenharmony_ci int frag1, frag2; 33618c2ecf20Sopenharmony_ci 33628c2ecf20Sopenharmony_ci frag1 = ath11k_dp_rx_h_mpdu_start_frag_no(a); 33638c2ecf20Sopenharmony_ci frag2 = ath11k_dp_rx_h_mpdu_start_frag_no(b); 33648c2ecf20Sopenharmony_ci 33658c2ecf20Sopenharmony_ci return frag1 - frag2; 33668c2ecf20Sopenharmony_ci} 33678c2ecf20Sopenharmony_ci 33688c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_sort_frags(struct sk_buff_head *frag_list, 33698c2ecf20Sopenharmony_ci struct sk_buff *cur_frag) 33708c2ecf20Sopenharmony_ci{ 33718c2ecf20Sopenharmony_ci struct sk_buff *skb; 33728c2ecf20Sopenharmony_ci int cmp; 33738c2ecf20Sopenharmony_ci 33748c2ecf20Sopenharmony_ci skb_queue_walk(frag_list, skb) { 33758c2ecf20Sopenharmony_ci cmp = ath11k_dp_rx_h_cmp_frags(skb, cur_frag); 33768c2ecf20Sopenharmony_ci if (cmp < 0) 33778c2ecf20Sopenharmony_ci continue; 33788c2ecf20Sopenharmony_ci __skb_queue_before(frag_list, skb, cur_frag); 33798c2ecf20Sopenharmony_ci return; 33808c2ecf20Sopenharmony_ci } 33818c2ecf20Sopenharmony_ci __skb_queue_tail(frag_list, cur_frag); 33828c2ecf20Sopenharmony_ci} 33838c2ecf20Sopenharmony_ci 33848c2ecf20Sopenharmony_cistatic u64 ath11k_dp_rx_h_get_pn(struct sk_buff *skb) 33858c2ecf20Sopenharmony_ci{ 33868c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 33878c2ecf20Sopenharmony_ci u64 pn = 0; 33888c2ecf20Sopenharmony_ci u8 *ehdr; 33898c2ecf20Sopenharmony_ci 33908c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)(skb->data + HAL_RX_DESC_SIZE); 33918c2ecf20Sopenharmony_ci ehdr = skb->data + HAL_RX_DESC_SIZE + ieee80211_hdrlen(hdr->frame_control); 33928c2ecf20Sopenharmony_ci 33938c2ecf20Sopenharmony_ci pn = ehdr[0]; 33948c2ecf20Sopenharmony_ci pn |= (u64)ehdr[1] << 8; 33958c2ecf20Sopenharmony_ci pn |= (u64)ehdr[4] << 16; 33968c2ecf20Sopenharmony_ci pn |= (u64)ehdr[5] << 24; 33978c2ecf20Sopenharmony_ci pn |= (u64)ehdr[6] << 32; 33988c2ecf20Sopenharmony_ci pn |= (u64)ehdr[7] << 40; 33998c2ecf20Sopenharmony_ci 34008c2ecf20Sopenharmony_ci return pn; 34018c2ecf20Sopenharmony_ci} 34028c2ecf20Sopenharmony_ci 34038c2ecf20Sopenharmony_cistatic bool 34048c2ecf20Sopenharmony_ciath11k_dp_rx_h_defrag_validate_incr_pn(struct ath11k *ar, struct dp_rx_tid *rx_tid) 34058c2ecf20Sopenharmony_ci{ 34068c2ecf20Sopenharmony_ci enum hal_encrypt_type encrypt_type; 34078c2ecf20Sopenharmony_ci struct sk_buff *first_frag, *skb; 34088c2ecf20Sopenharmony_ci struct hal_rx_desc *desc; 34098c2ecf20Sopenharmony_ci u64 last_pn; 34108c2ecf20Sopenharmony_ci u64 cur_pn; 34118c2ecf20Sopenharmony_ci 34128c2ecf20Sopenharmony_ci first_frag = skb_peek(&rx_tid->rx_frags); 34138c2ecf20Sopenharmony_ci desc = (struct hal_rx_desc *)first_frag->data; 34148c2ecf20Sopenharmony_ci 34158c2ecf20Sopenharmony_ci encrypt_type = ath11k_dp_rx_h_mpdu_start_enctype(desc); 34168c2ecf20Sopenharmony_ci if (encrypt_type != HAL_ENCRYPT_TYPE_CCMP_128 && 34178c2ecf20Sopenharmony_ci encrypt_type != HAL_ENCRYPT_TYPE_CCMP_256 && 34188c2ecf20Sopenharmony_ci encrypt_type != HAL_ENCRYPT_TYPE_GCMP_128 && 34198c2ecf20Sopenharmony_ci encrypt_type != HAL_ENCRYPT_TYPE_AES_GCMP_256) 34208c2ecf20Sopenharmony_ci return true; 34218c2ecf20Sopenharmony_ci 34228c2ecf20Sopenharmony_ci last_pn = ath11k_dp_rx_h_get_pn(first_frag); 34238c2ecf20Sopenharmony_ci skb_queue_walk(&rx_tid->rx_frags, skb) { 34248c2ecf20Sopenharmony_ci if (skb == first_frag) 34258c2ecf20Sopenharmony_ci continue; 34268c2ecf20Sopenharmony_ci 34278c2ecf20Sopenharmony_ci cur_pn = ath11k_dp_rx_h_get_pn(skb); 34288c2ecf20Sopenharmony_ci if (cur_pn != last_pn + 1) 34298c2ecf20Sopenharmony_ci return false; 34308c2ecf20Sopenharmony_ci last_pn = cur_pn; 34318c2ecf20Sopenharmony_ci } 34328c2ecf20Sopenharmony_ci return true; 34338c2ecf20Sopenharmony_ci} 34348c2ecf20Sopenharmony_ci 34358c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_frag_h_mpdu(struct ath11k *ar, 34368c2ecf20Sopenharmony_ci struct sk_buff *msdu, 34378c2ecf20Sopenharmony_ci u32 *ring_desc) 34388c2ecf20Sopenharmony_ci{ 34398c2ecf20Sopenharmony_ci struct ath11k_base *ab = ar->ab; 34408c2ecf20Sopenharmony_ci struct hal_rx_desc *rx_desc; 34418c2ecf20Sopenharmony_ci struct ath11k_peer *peer; 34428c2ecf20Sopenharmony_ci struct dp_rx_tid *rx_tid; 34438c2ecf20Sopenharmony_ci struct sk_buff *defrag_skb = NULL; 34448c2ecf20Sopenharmony_ci u32 peer_id; 34458c2ecf20Sopenharmony_ci u16 seqno, frag_no; 34468c2ecf20Sopenharmony_ci u8 tid; 34478c2ecf20Sopenharmony_ci int ret = 0; 34488c2ecf20Sopenharmony_ci bool more_frags; 34498c2ecf20Sopenharmony_ci 34508c2ecf20Sopenharmony_ci rx_desc = (struct hal_rx_desc *)msdu->data; 34518c2ecf20Sopenharmony_ci peer_id = ath11k_dp_rx_h_mpdu_start_peer_id(rx_desc); 34528c2ecf20Sopenharmony_ci tid = ath11k_dp_rx_h_mpdu_start_tid(rx_desc); 34538c2ecf20Sopenharmony_ci seqno = ath11k_dp_rx_h_mpdu_start_seq_no(rx_desc); 34548c2ecf20Sopenharmony_ci frag_no = ath11k_dp_rx_h_mpdu_start_frag_no(msdu); 34558c2ecf20Sopenharmony_ci more_frags = ath11k_dp_rx_h_mpdu_start_more_frags(msdu); 34568c2ecf20Sopenharmony_ci 34578c2ecf20Sopenharmony_ci if (!ath11k_dp_rx_h_mpdu_start_seq_ctrl_valid(rx_desc) || 34588c2ecf20Sopenharmony_ci !ath11k_dp_rx_h_mpdu_start_fc_valid(rx_desc) || 34598c2ecf20Sopenharmony_ci tid > IEEE80211_NUM_TIDS) 34608c2ecf20Sopenharmony_ci return -EINVAL; 34618c2ecf20Sopenharmony_ci 34628c2ecf20Sopenharmony_ci /* received unfragmented packet in reo 34638c2ecf20Sopenharmony_ci * exception ring, this shouldn't happen 34648c2ecf20Sopenharmony_ci * as these packets typically come from 34658c2ecf20Sopenharmony_ci * reo2sw srngs. 34668c2ecf20Sopenharmony_ci */ 34678c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!frag_no && !more_frags)) 34688c2ecf20Sopenharmony_ci return -EINVAL; 34698c2ecf20Sopenharmony_ci 34708c2ecf20Sopenharmony_ci spin_lock_bh(&ab->base_lock); 34718c2ecf20Sopenharmony_ci peer = ath11k_peer_find_by_id(ab, peer_id); 34728c2ecf20Sopenharmony_ci if (!peer) { 34738c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to find the peer to de-fragment received fragment peer_id %d\n", 34748c2ecf20Sopenharmony_ci peer_id); 34758c2ecf20Sopenharmony_ci ret = -ENOENT; 34768c2ecf20Sopenharmony_ci goto out_unlock; 34778c2ecf20Sopenharmony_ci } 34788c2ecf20Sopenharmony_ci rx_tid = &peer->rx_tid[tid]; 34798c2ecf20Sopenharmony_ci 34808c2ecf20Sopenharmony_ci if ((!skb_queue_empty(&rx_tid->rx_frags) && seqno != rx_tid->cur_sn) || 34818c2ecf20Sopenharmony_ci skb_queue_empty(&rx_tid->rx_frags)) { 34828c2ecf20Sopenharmony_ci /* Flush stored fragments and start a new sequence */ 34838c2ecf20Sopenharmony_ci ath11k_dp_rx_frags_cleanup(rx_tid, true); 34848c2ecf20Sopenharmony_ci rx_tid->cur_sn = seqno; 34858c2ecf20Sopenharmony_ci } 34868c2ecf20Sopenharmony_ci 34878c2ecf20Sopenharmony_ci if (rx_tid->rx_frag_bitmap & BIT(frag_no)) { 34888c2ecf20Sopenharmony_ci /* Fragment already present */ 34898c2ecf20Sopenharmony_ci ret = -EINVAL; 34908c2ecf20Sopenharmony_ci goto out_unlock; 34918c2ecf20Sopenharmony_ci } 34928c2ecf20Sopenharmony_ci 34938c2ecf20Sopenharmony_ci if (frag_no > __fls(rx_tid->rx_frag_bitmap)) 34948c2ecf20Sopenharmony_ci __skb_queue_tail(&rx_tid->rx_frags, msdu); 34958c2ecf20Sopenharmony_ci else 34968c2ecf20Sopenharmony_ci ath11k_dp_rx_h_sort_frags(&rx_tid->rx_frags, msdu); 34978c2ecf20Sopenharmony_ci 34988c2ecf20Sopenharmony_ci rx_tid->rx_frag_bitmap |= BIT(frag_no); 34998c2ecf20Sopenharmony_ci if (!more_frags) 35008c2ecf20Sopenharmony_ci rx_tid->last_frag_no = frag_no; 35018c2ecf20Sopenharmony_ci 35028c2ecf20Sopenharmony_ci if (frag_no == 0) { 35038c2ecf20Sopenharmony_ci rx_tid->dst_ring_desc = kmemdup(ring_desc, 35048c2ecf20Sopenharmony_ci sizeof(*rx_tid->dst_ring_desc), 35058c2ecf20Sopenharmony_ci GFP_ATOMIC); 35068c2ecf20Sopenharmony_ci if (!rx_tid->dst_ring_desc) { 35078c2ecf20Sopenharmony_ci ret = -ENOMEM; 35088c2ecf20Sopenharmony_ci goto out_unlock; 35098c2ecf20Sopenharmony_ci } 35108c2ecf20Sopenharmony_ci } else { 35118c2ecf20Sopenharmony_ci ath11k_dp_rx_link_desc_return(ab, ring_desc, 35128c2ecf20Sopenharmony_ci HAL_WBM_REL_BM_ACT_PUT_IN_IDLE); 35138c2ecf20Sopenharmony_ci } 35148c2ecf20Sopenharmony_ci 35158c2ecf20Sopenharmony_ci if (!rx_tid->last_frag_no || 35168c2ecf20Sopenharmony_ci rx_tid->rx_frag_bitmap != GENMASK(rx_tid->last_frag_no, 0)) { 35178c2ecf20Sopenharmony_ci mod_timer(&rx_tid->frag_timer, jiffies + 35188c2ecf20Sopenharmony_ci ATH11K_DP_RX_FRAGMENT_TIMEOUT_MS); 35198c2ecf20Sopenharmony_ci goto out_unlock; 35208c2ecf20Sopenharmony_ci } 35218c2ecf20Sopenharmony_ci 35228c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 35238c2ecf20Sopenharmony_ci del_timer_sync(&rx_tid->frag_timer); 35248c2ecf20Sopenharmony_ci spin_lock_bh(&ab->base_lock); 35258c2ecf20Sopenharmony_ci 35268c2ecf20Sopenharmony_ci peer = ath11k_peer_find_by_id(ab, peer_id); 35278c2ecf20Sopenharmony_ci if (!peer) 35288c2ecf20Sopenharmony_ci goto err_frags_cleanup; 35298c2ecf20Sopenharmony_ci 35308c2ecf20Sopenharmony_ci if (!ath11k_dp_rx_h_defrag_validate_incr_pn(ar, rx_tid)) 35318c2ecf20Sopenharmony_ci goto err_frags_cleanup; 35328c2ecf20Sopenharmony_ci 35338c2ecf20Sopenharmony_ci if (ath11k_dp_rx_h_defrag(ar, peer, rx_tid, &defrag_skb)) 35348c2ecf20Sopenharmony_ci goto err_frags_cleanup; 35358c2ecf20Sopenharmony_ci 35368c2ecf20Sopenharmony_ci if (!defrag_skb) 35378c2ecf20Sopenharmony_ci goto err_frags_cleanup; 35388c2ecf20Sopenharmony_ci 35398c2ecf20Sopenharmony_ci if (ath11k_dp_rx_h_defrag_reo_reinject(ar, rx_tid, defrag_skb)) 35408c2ecf20Sopenharmony_ci goto err_frags_cleanup; 35418c2ecf20Sopenharmony_ci 35428c2ecf20Sopenharmony_ci ath11k_dp_rx_frags_cleanup(rx_tid, false); 35438c2ecf20Sopenharmony_ci goto out_unlock; 35448c2ecf20Sopenharmony_ci 35458c2ecf20Sopenharmony_cierr_frags_cleanup: 35468c2ecf20Sopenharmony_ci dev_kfree_skb_any(defrag_skb); 35478c2ecf20Sopenharmony_ci ath11k_dp_rx_frags_cleanup(rx_tid, true); 35488c2ecf20Sopenharmony_ciout_unlock: 35498c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 35508c2ecf20Sopenharmony_ci return ret; 35518c2ecf20Sopenharmony_ci} 35528c2ecf20Sopenharmony_ci 35538c2ecf20Sopenharmony_cistatic int 35548c2ecf20Sopenharmony_ciath11k_dp_process_rx_err_buf(struct ath11k *ar, u32 *ring_desc, int buf_id, bool drop) 35558c2ecf20Sopenharmony_ci{ 35568c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp = &ar->dp; 35578c2ecf20Sopenharmony_ci struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; 35588c2ecf20Sopenharmony_ci struct sk_buff *msdu; 35598c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb; 35608c2ecf20Sopenharmony_ci struct hal_rx_desc *rx_desc; 35618c2ecf20Sopenharmony_ci u8 *hdr_status; 35628c2ecf20Sopenharmony_ci u16 msdu_len; 35638c2ecf20Sopenharmony_ci 35648c2ecf20Sopenharmony_ci spin_lock_bh(&rx_ring->idr_lock); 35658c2ecf20Sopenharmony_ci msdu = idr_find(&rx_ring->bufs_idr, buf_id); 35668c2ecf20Sopenharmony_ci if (!msdu) { 35678c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "rx err buf with invalid buf_id %d\n", 35688c2ecf20Sopenharmony_ci buf_id); 35698c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 35708c2ecf20Sopenharmony_ci return -EINVAL; 35718c2ecf20Sopenharmony_ci } 35728c2ecf20Sopenharmony_ci 35738c2ecf20Sopenharmony_ci idr_remove(&rx_ring->bufs_idr, buf_id); 35748c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 35758c2ecf20Sopenharmony_ci 35768c2ecf20Sopenharmony_ci rxcb = ATH11K_SKB_RXCB(msdu); 35778c2ecf20Sopenharmony_ci dma_unmap_single(ar->ab->dev, rxcb->paddr, 35788c2ecf20Sopenharmony_ci msdu->len + skb_tailroom(msdu), 35798c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 35808c2ecf20Sopenharmony_ci 35818c2ecf20Sopenharmony_ci if (drop) { 35828c2ecf20Sopenharmony_ci dev_kfree_skb_any(msdu); 35838c2ecf20Sopenharmony_ci return 0; 35848c2ecf20Sopenharmony_ci } 35858c2ecf20Sopenharmony_ci 35868c2ecf20Sopenharmony_ci rcu_read_lock(); 35878c2ecf20Sopenharmony_ci if (!rcu_dereference(ar->ab->pdevs_active[ar->pdev_idx])) { 35888c2ecf20Sopenharmony_ci dev_kfree_skb_any(msdu); 35898c2ecf20Sopenharmony_ci goto exit; 35908c2ecf20Sopenharmony_ci } 35918c2ecf20Sopenharmony_ci 35928c2ecf20Sopenharmony_ci if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) { 35938c2ecf20Sopenharmony_ci dev_kfree_skb_any(msdu); 35948c2ecf20Sopenharmony_ci goto exit; 35958c2ecf20Sopenharmony_ci } 35968c2ecf20Sopenharmony_ci 35978c2ecf20Sopenharmony_ci rx_desc = (struct hal_rx_desc *)msdu->data; 35988c2ecf20Sopenharmony_ci msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(rx_desc); 35998c2ecf20Sopenharmony_ci if ((msdu_len + HAL_RX_DESC_SIZE) > DP_RX_BUFFER_SIZE) { 36008c2ecf20Sopenharmony_ci hdr_status = ath11k_dp_rx_h_80211_hdr(rx_desc); 36018c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "invalid msdu leng %u", msdu_len); 36028c2ecf20Sopenharmony_ci ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", hdr_status, 36038c2ecf20Sopenharmony_ci sizeof(struct ieee80211_hdr)); 36048c2ecf20Sopenharmony_ci ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", rx_desc, 36058c2ecf20Sopenharmony_ci sizeof(struct hal_rx_desc)); 36068c2ecf20Sopenharmony_ci dev_kfree_skb_any(msdu); 36078c2ecf20Sopenharmony_ci goto exit; 36088c2ecf20Sopenharmony_ci } 36098c2ecf20Sopenharmony_ci 36108c2ecf20Sopenharmony_ci skb_put(msdu, HAL_RX_DESC_SIZE + msdu_len); 36118c2ecf20Sopenharmony_ci 36128c2ecf20Sopenharmony_ci if (ath11k_dp_rx_frag_h_mpdu(ar, msdu, ring_desc)) { 36138c2ecf20Sopenharmony_ci dev_kfree_skb_any(msdu); 36148c2ecf20Sopenharmony_ci ath11k_dp_rx_link_desc_return(ar->ab, ring_desc, 36158c2ecf20Sopenharmony_ci HAL_WBM_REL_BM_ACT_PUT_IN_IDLE); 36168c2ecf20Sopenharmony_ci } 36178c2ecf20Sopenharmony_ciexit: 36188c2ecf20Sopenharmony_ci rcu_read_unlock(); 36198c2ecf20Sopenharmony_ci return 0; 36208c2ecf20Sopenharmony_ci} 36218c2ecf20Sopenharmony_ci 36228c2ecf20Sopenharmony_ciint ath11k_dp_process_rx_err(struct ath11k_base *ab, struct napi_struct *napi, 36238c2ecf20Sopenharmony_ci int budget) 36248c2ecf20Sopenharmony_ci{ 36258c2ecf20Sopenharmony_ci u32 msdu_cookies[HAL_NUM_RX_MSDUS_PER_LINK_DESC]; 36268c2ecf20Sopenharmony_ci struct dp_link_desc_bank *link_desc_banks; 36278c2ecf20Sopenharmony_ci enum hal_rx_buf_return_buf_manager rbm; 36288c2ecf20Sopenharmony_ci int tot_n_bufs_reaped, quota, ret, i; 36298c2ecf20Sopenharmony_ci int n_bufs_reaped[MAX_RADIOS] = {0}; 36308c2ecf20Sopenharmony_ci struct dp_rxdma_ring *rx_ring; 36318c2ecf20Sopenharmony_ci struct dp_srng *reo_except; 36328c2ecf20Sopenharmony_ci u32 desc_bank, num_msdus; 36338c2ecf20Sopenharmony_ci struct hal_srng *srng; 36348c2ecf20Sopenharmony_ci struct ath11k_dp *dp; 36358c2ecf20Sopenharmony_ci void *link_desc_va; 36368c2ecf20Sopenharmony_ci int buf_id, mac_id; 36378c2ecf20Sopenharmony_ci struct ath11k *ar; 36388c2ecf20Sopenharmony_ci dma_addr_t paddr; 36398c2ecf20Sopenharmony_ci u32 *desc; 36408c2ecf20Sopenharmony_ci bool is_frag; 36418c2ecf20Sopenharmony_ci u8 drop = 0; 36428c2ecf20Sopenharmony_ci 36438c2ecf20Sopenharmony_ci tot_n_bufs_reaped = 0; 36448c2ecf20Sopenharmony_ci quota = budget; 36458c2ecf20Sopenharmony_ci 36468c2ecf20Sopenharmony_ci dp = &ab->dp; 36478c2ecf20Sopenharmony_ci reo_except = &dp->reo_except_ring; 36488c2ecf20Sopenharmony_ci link_desc_banks = dp->link_desc_banks; 36498c2ecf20Sopenharmony_ci 36508c2ecf20Sopenharmony_ci srng = &ab->hal.srng_list[reo_except->ring_id]; 36518c2ecf20Sopenharmony_ci 36528c2ecf20Sopenharmony_ci spin_lock_bh(&srng->lock); 36538c2ecf20Sopenharmony_ci 36548c2ecf20Sopenharmony_ci ath11k_hal_srng_access_begin(ab, srng); 36558c2ecf20Sopenharmony_ci 36568c2ecf20Sopenharmony_ci while (budget && 36578c2ecf20Sopenharmony_ci (desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) { 36588c2ecf20Sopenharmony_ci struct hal_reo_dest_ring *reo_desc = (struct hal_reo_dest_ring *)desc; 36598c2ecf20Sopenharmony_ci 36608c2ecf20Sopenharmony_ci ab->soc_stats.err_ring_pkts++; 36618c2ecf20Sopenharmony_ci ret = ath11k_hal_desc_reo_parse_err(ab, desc, &paddr, 36628c2ecf20Sopenharmony_ci &desc_bank); 36638c2ecf20Sopenharmony_ci if (ret) { 36648c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to parse error reo desc %d\n", 36658c2ecf20Sopenharmony_ci ret); 36668c2ecf20Sopenharmony_ci continue; 36678c2ecf20Sopenharmony_ci } 36688c2ecf20Sopenharmony_ci link_desc_va = link_desc_banks[desc_bank].vaddr + 36698c2ecf20Sopenharmony_ci (paddr - link_desc_banks[desc_bank].paddr); 36708c2ecf20Sopenharmony_ci ath11k_hal_rx_msdu_link_info_get(link_desc_va, &num_msdus, msdu_cookies, 36718c2ecf20Sopenharmony_ci &rbm); 36728c2ecf20Sopenharmony_ci if (rbm != HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST && 36738c2ecf20Sopenharmony_ci rbm != HAL_RX_BUF_RBM_SW3_BM) { 36748c2ecf20Sopenharmony_ci ab->soc_stats.invalid_rbm++; 36758c2ecf20Sopenharmony_ci ath11k_warn(ab, "invalid return buffer manager %d\n", rbm); 36768c2ecf20Sopenharmony_ci ath11k_dp_rx_link_desc_return(ab, desc, 36778c2ecf20Sopenharmony_ci HAL_WBM_REL_BM_ACT_REL_MSDU); 36788c2ecf20Sopenharmony_ci continue; 36798c2ecf20Sopenharmony_ci } 36808c2ecf20Sopenharmony_ci 36818c2ecf20Sopenharmony_ci is_frag = !!(reo_desc->rx_mpdu_info.info0 & RX_MPDU_DESC_INFO0_FRAG_FLAG); 36828c2ecf20Sopenharmony_ci 36838c2ecf20Sopenharmony_ci /* Process only rx fragments with one msdu per link desc below, and drop 36848c2ecf20Sopenharmony_ci * msdu's indicated due to error reasons. 36858c2ecf20Sopenharmony_ci */ 36868c2ecf20Sopenharmony_ci if (!is_frag || num_msdus > 1) { 36878c2ecf20Sopenharmony_ci drop = 1; 36888c2ecf20Sopenharmony_ci /* Return the link desc back to wbm idle list */ 36898c2ecf20Sopenharmony_ci ath11k_dp_rx_link_desc_return(ab, desc, 36908c2ecf20Sopenharmony_ci HAL_WBM_REL_BM_ACT_PUT_IN_IDLE); 36918c2ecf20Sopenharmony_ci } 36928c2ecf20Sopenharmony_ci 36938c2ecf20Sopenharmony_ci for (i = 0; i < num_msdus; i++) { 36948c2ecf20Sopenharmony_ci buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, 36958c2ecf20Sopenharmony_ci msdu_cookies[i]); 36968c2ecf20Sopenharmony_ci 36978c2ecf20Sopenharmony_ci mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, 36988c2ecf20Sopenharmony_ci msdu_cookies[i]); 36998c2ecf20Sopenharmony_ci 37008c2ecf20Sopenharmony_ci ar = ab->pdevs[mac_id].ar; 37018c2ecf20Sopenharmony_ci 37028c2ecf20Sopenharmony_ci if (!ath11k_dp_process_rx_err_buf(ar, desc, buf_id, drop)) { 37038c2ecf20Sopenharmony_ci n_bufs_reaped[mac_id]++; 37048c2ecf20Sopenharmony_ci tot_n_bufs_reaped++; 37058c2ecf20Sopenharmony_ci } 37068c2ecf20Sopenharmony_ci } 37078c2ecf20Sopenharmony_ci 37088c2ecf20Sopenharmony_ci if (tot_n_bufs_reaped >= quota) { 37098c2ecf20Sopenharmony_ci tot_n_bufs_reaped = quota; 37108c2ecf20Sopenharmony_ci goto exit; 37118c2ecf20Sopenharmony_ci } 37128c2ecf20Sopenharmony_ci 37138c2ecf20Sopenharmony_ci budget = quota - tot_n_bufs_reaped; 37148c2ecf20Sopenharmony_ci } 37158c2ecf20Sopenharmony_ci 37168c2ecf20Sopenharmony_ciexit: 37178c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 37188c2ecf20Sopenharmony_ci 37198c2ecf20Sopenharmony_ci spin_unlock_bh(&srng->lock); 37208c2ecf20Sopenharmony_ci 37218c2ecf20Sopenharmony_ci for (i = 0; i < ab->num_radios; i++) { 37228c2ecf20Sopenharmony_ci if (!n_bufs_reaped[i]) 37238c2ecf20Sopenharmony_ci continue; 37248c2ecf20Sopenharmony_ci 37258c2ecf20Sopenharmony_ci ar = ab->pdevs[i].ar; 37268c2ecf20Sopenharmony_ci rx_ring = &ar->dp.rx_refill_buf_ring; 37278c2ecf20Sopenharmony_ci 37288c2ecf20Sopenharmony_ci ath11k_dp_rxbufs_replenish(ab, i, rx_ring, n_bufs_reaped[i], 37298c2ecf20Sopenharmony_ci HAL_RX_BUF_RBM_SW3_BM); 37308c2ecf20Sopenharmony_ci } 37318c2ecf20Sopenharmony_ci 37328c2ecf20Sopenharmony_ci return tot_n_bufs_reaped; 37338c2ecf20Sopenharmony_ci} 37348c2ecf20Sopenharmony_ci 37358c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_null_q_desc_sg_drop(struct ath11k *ar, 37368c2ecf20Sopenharmony_ci int msdu_len, 37378c2ecf20Sopenharmony_ci struct sk_buff_head *msdu_list) 37388c2ecf20Sopenharmony_ci{ 37398c2ecf20Sopenharmony_ci struct sk_buff *skb, *tmp; 37408c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb; 37418c2ecf20Sopenharmony_ci int n_buffs; 37428c2ecf20Sopenharmony_ci 37438c2ecf20Sopenharmony_ci n_buffs = DIV_ROUND_UP(msdu_len, 37448c2ecf20Sopenharmony_ci (DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE)); 37458c2ecf20Sopenharmony_ci 37468c2ecf20Sopenharmony_ci skb_queue_walk_safe(msdu_list, skb, tmp) { 37478c2ecf20Sopenharmony_ci rxcb = ATH11K_SKB_RXCB(skb); 37488c2ecf20Sopenharmony_ci if (rxcb->err_rel_src == HAL_WBM_REL_SRC_MODULE_REO && 37498c2ecf20Sopenharmony_ci rxcb->err_code == HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO) { 37508c2ecf20Sopenharmony_ci if (!n_buffs) 37518c2ecf20Sopenharmony_ci break; 37528c2ecf20Sopenharmony_ci __skb_unlink(skb, msdu_list); 37538c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 37548c2ecf20Sopenharmony_ci n_buffs--; 37558c2ecf20Sopenharmony_ci } 37568c2ecf20Sopenharmony_ci } 37578c2ecf20Sopenharmony_ci} 37588c2ecf20Sopenharmony_ci 37598c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_h_null_q_desc(struct ath11k *ar, struct sk_buff *msdu, 37608c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status, 37618c2ecf20Sopenharmony_ci struct sk_buff_head *msdu_list) 37628c2ecf20Sopenharmony_ci{ 37638c2ecf20Sopenharmony_ci u16 msdu_len; 37648c2ecf20Sopenharmony_ci struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data; 37658c2ecf20Sopenharmony_ci u8 l3pad_bytes; 37668c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 37678c2ecf20Sopenharmony_ci 37688c2ecf20Sopenharmony_ci msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(desc); 37698c2ecf20Sopenharmony_ci 37708c2ecf20Sopenharmony_ci if (!rxcb->is_frag && ((msdu_len + HAL_RX_DESC_SIZE) > DP_RX_BUFFER_SIZE)) { 37718c2ecf20Sopenharmony_ci /* First buffer will be freed by the caller, so deduct it's length */ 37728c2ecf20Sopenharmony_ci msdu_len = msdu_len - (DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE); 37738c2ecf20Sopenharmony_ci ath11k_dp_rx_null_q_desc_sg_drop(ar, msdu_len, msdu_list); 37748c2ecf20Sopenharmony_ci return -EINVAL; 37758c2ecf20Sopenharmony_ci } 37768c2ecf20Sopenharmony_ci 37778c2ecf20Sopenharmony_ci if (!ath11k_dp_rx_h_attn_msdu_done(desc)) { 37788c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, 37798c2ecf20Sopenharmony_ci "msdu_done bit not set in null_q_des processing\n"); 37808c2ecf20Sopenharmony_ci __skb_queue_purge(msdu_list); 37818c2ecf20Sopenharmony_ci return -EIO; 37828c2ecf20Sopenharmony_ci } 37838c2ecf20Sopenharmony_ci 37848c2ecf20Sopenharmony_ci /* Handle NULL queue descriptor violations arising out a missing 37858c2ecf20Sopenharmony_ci * REO queue for a given peer or a given TID. This typically 37868c2ecf20Sopenharmony_ci * may happen if a packet is received on a QOS enabled TID before the 37878c2ecf20Sopenharmony_ci * ADDBA negotiation for that TID, when the TID queue is setup. Or 37888c2ecf20Sopenharmony_ci * it may also happen for MC/BC frames if they are not routed to the 37898c2ecf20Sopenharmony_ci * non-QOS TID queue, in the absence of any other default TID queue. 37908c2ecf20Sopenharmony_ci * This error can show up both in a REO destination or WBM release ring. 37918c2ecf20Sopenharmony_ci */ 37928c2ecf20Sopenharmony_ci 37938c2ecf20Sopenharmony_ci rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(desc); 37948c2ecf20Sopenharmony_ci rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(desc); 37958c2ecf20Sopenharmony_ci 37968c2ecf20Sopenharmony_ci if (rxcb->is_frag) { 37978c2ecf20Sopenharmony_ci skb_pull(msdu, HAL_RX_DESC_SIZE); 37988c2ecf20Sopenharmony_ci } else { 37998c2ecf20Sopenharmony_ci l3pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(desc); 38008c2ecf20Sopenharmony_ci 38018c2ecf20Sopenharmony_ci if ((HAL_RX_DESC_SIZE + l3pad_bytes + msdu_len) > DP_RX_BUFFER_SIZE) 38028c2ecf20Sopenharmony_ci return -EINVAL; 38038c2ecf20Sopenharmony_ci 38048c2ecf20Sopenharmony_ci skb_put(msdu, HAL_RX_DESC_SIZE + l3pad_bytes + msdu_len); 38058c2ecf20Sopenharmony_ci skb_pull(msdu, HAL_RX_DESC_SIZE + l3pad_bytes); 38068c2ecf20Sopenharmony_ci } 38078c2ecf20Sopenharmony_ci ath11k_dp_rx_h_ppdu(ar, desc, status); 38088c2ecf20Sopenharmony_ci 38098c2ecf20Sopenharmony_ci ath11k_dp_rx_h_mpdu(ar, msdu, desc, status); 38108c2ecf20Sopenharmony_ci 38118c2ecf20Sopenharmony_ci rxcb->tid = ath11k_dp_rx_h_mpdu_start_tid(desc); 38128c2ecf20Sopenharmony_ci 38138c2ecf20Sopenharmony_ci /* Please note that caller will having the access to msdu and completing 38148c2ecf20Sopenharmony_ci * rx with mac80211. Need not worry about cleaning up amsdu_list. 38158c2ecf20Sopenharmony_ci */ 38168c2ecf20Sopenharmony_ci 38178c2ecf20Sopenharmony_ci return 0; 38188c2ecf20Sopenharmony_ci} 38198c2ecf20Sopenharmony_ci 38208c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_reo_err(struct ath11k *ar, struct sk_buff *msdu, 38218c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status, 38228c2ecf20Sopenharmony_ci struct sk_buff_head *msdu_list) 38238c2ecf20Sopenharmony_ci{ 38248c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 38258c2ecf20Sopenharmony_ci bool drop = false; 38268c2ecf20Sopenharmony_ci 38278c2ecf20Sopenharmony_ci ar->ab->soc_stats.reo_error[rxcb->err_code]++; 38288c2ecf20Sopenharmony_ci 38298c2ecf20Sopenharmony_ci switch (rxcb->err_code) { 38308c2ecf20Sopenharmony_ci case HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO: 38318c2ecf20Sopenharmony_ci if (ath11k_dp_rx_h_null_q_desc(ar, msdu, status, msdu_list)) 38328c2ecf20Sopenharmony_ci drop = true; 38338c2ecf20Sopenharmony_ci break; 38348c2ecf20Sopenharmony_ci case HAL_REO_DEST_RING_ERROR_CODE_PN_CHECK_FAILED: 38358c2ecf20Sopenharmony_ci /* TODO: Do not drop PN failed packets in the driver; 38368c2ecf20Sopenharmony_ci * instead, it is good to drop such packets in mac80211 38378c2ecf20Sopenharmony_ci * after incrementing the replay counters. 38388c2ecf20Sopenharmony_ci */ 38398c2ecf20Sopenharmony_ci fallthrough; 38408c2ecf20Sopenharmony_ci default: 38418c2ecf20Sopenharmony_ci /* TODO: Review other errors and process them to mac80211 38428c2ecf20Sopenharmony_ci * as appropriate. 38438c2ecf20Sopenharmony_ci */ 38448c2ecf20Sopenharmony_ci drop = true; 38458c2ecf20Sopenharmony_ci break; 38468c2ecf20Sopenharmony_ci } 38478c2ecf20Sopenharmony_ci 38488c2ecf20Sopenharmony_ci return drop; 38498c2ecf20Sopenharmony_ci} 38508c2ecf20Sopenharmony_ci 38518c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu, 38528c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status) 38538c2ecf20Sopenharmony_ci{ 38548c2ecf20Sopenharmony_ci u16 msdu_len; 38558c2ecf20Sopenharmony_ci struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data; 38568c2ecf20Sopenharmony_ci u8 l3pad_bytes; 38578c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 38588c2ecf20Sopenharmony_ci 38598c2ecf20Sopenharmony_ci rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(desc); 38608c2ecf20Sopenharmony_ci rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(desc); 38618c2ecf20Sopenharmony_ci 38628c2ecf20Sopenharmony_ci l3pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(desc); 38638c2ecf20Sopenharmony_ci msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(desc); 38648c2ecf20Sopenharmony_ci skb_put(msdu, HAL_RX_DESC_SIZE + l3pad_bytes + msdu_len); 38658c2ecf20Sopenharmony_ci skb_pull(msdu, HAL_RX_DESC_SIZE + l3pad_bytes); 38668c2ecf20Sopenharmony_ci 38678c2ecf20Sopenharmony_ci ath11k_dp_rx_h_ppdu(ar, desc, status); 38688c2ecf20Sopenharmony_ci 38698c2ecf20Sopenharmony_ci status->flag |= (RX_FLAG_MMIC_STRIPPED | RX_FLAG_MMIC_ERROR | 38708c2ecf20Sopenharmony_ci RX_FLAG_DECRYPTED); 38718c2ecf20Sopenharmony_ci 38728c2ecf20Sopenharmony_ci ath11k_dp_rx_h_undecap(ar, msdu, desc, 38738c2ecf20Sopenharmony_ci HAL_ENCRYPT_TYPE_TKIP_MIC, status, false); 38748c2ecf20Sopenharmony_ci} 38758c2ecf20Sopenharmony_ci 38768c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_rxdma_err(struct ath11k *ar, struct sk_buff *msdu, 38778c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status) 38788c2ecf20Sopenharmony_ci{ 38798c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 38808c2ecf20Sopenharmony_ci bool drop = false; 38818c2ecf20Sopenharmony_ci 38828c2ecf20Sopenharmony_ci ar->ab->soc_stats.rxdma_error[rxcb->err_code]++; 38838c2ecf20Sopenharmony_ci 38848c2ecf20Sopenharmony_ci switch (rxcb->err_code) { 38858c2ecf20Sopenharmony_ci case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR: 38868c2ecf20Sopenharmony_ci ath11k_dp_rx_h_tkip_mic_err(ar, msdu, status); 38878c2ecf20Sopenharmony_ci break; 38888c2ecf20Sopenharmony_ci default: 38898c2ecf20Sopenharmony_ci /* TODO: Review other rxdma error code to check if anything is 38908c2ecf20Sopenharmony_ci * worth reporting to mac80211 38918c2ecf20Sopenharmony_ci */ 38928c2ecf20Sopenharmony_ci drop = true; 38938c2ecf20Sopenharmony_ci break; 38948c2ecf20Sopenharmony_ci } 38958c2ecf20Sopenharmony_ci 38968c2ecf20Sopenharmony_ci return drop; 38978c2ecf20Sopenharmony_ci} 38988c2ecf20Sopenharmony_ci 38998c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_wbm_err(struct ath11k *ar, 39008c2ecf20Sopenharmony_ci struct napi_struct *napi, 39018c2ecf20Sopenharmony_ci struct sk_buff *msdu, 39028c2ecf20Sopenharmony_ci struct sk_buff_head *msdu_list) 39038c2ecf20Sopenharmony_ci{ 39048c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); 39058c2ecf20Sopenharmony_ci struct ieee80211_rx_status rxs = {0}; 39068c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status; 39078c2ecf20Sopenharmony_ci bool drop = true; 39088c2ecf20Sopenharmony_ci 39098c2ecf20Sopenharmony_ci switch (rxcb->err_rel_src) { 39108c2ecf20Sopenharmony_ci case HAL_WBM_REL_SRC_MODULE_REO: 39118c2ecf20Sopenharmony_ci drop = ath11k_dp_rx_h_reo_err(ar, msdu, &rxs, msdu_list); 39128c2ecf20Sopenharmony_ci break; 39138c2ecf20Sopenharmony_ci case HAL_WBM_REL_SRC_MODULE_RXDMA: 39148c2ecf20Sopenharmony_ci drop = ath11k_dp_rx_h_rxdma_err(ar, msdu, &rxs); 39158c2ecf20Sopenharmony_ci break; 39168c2ecf20Sopenharmony_ci default: 39178c2ecf20Sopenharmony_ci /* msdu will get freed */ 39188c2ecf20Sopenharmony_ci break; 39198c2ecf20Sopenharmony_ci } 39208c2ecf20Sopenharmony_ci 39218c2ecf20Sopenharmony_ci if (drop) { 39228c2ecf20Sopenharmony_ci dev_kfree_skb_any(msdu); 39238c2ecf20Sopenharmony_ci return; 39248c2ecf20Sopenharmony_ci } 39258c2ecf20Sopenharmony_ci 39268c2ecf20Sopenharmony_ci status = IEEE80211_SKB_RXCB(msdu); 39278c2ecf20Sopenharmony_ci *status = rxs; 39288c2ecf20Sopenharmony_ci 39298c2ecf20Sopenharmony_ci ath11k_dp_rx_deliver_msdu(ar, napi, msdu); 39308c2ecf20Sopenharmony_ci} 39318c2ecf20Sopenharmony_ci 39328c2ecf20Sopenharmony_ciint ath11k_dp_rx_process_wbm_err(struct ath11k_base *ab, 39338c2ecf20Sopenharmony_ci struct napi_struct *napi, int budget) 39348c2ecf20Sopenharmony_ci{ 39358c2ecf20Sopenharmony_ci struct ath11k *ar; 39368c2ecf20Sopenharmony_ci struct ath11k_dp *dp = &ab->dp; 39378c2ecf20Sopenharmony_ci struct dp_rxdma_ring *rx_ring; 39388c2ecf20Sopenharmony_ci struct hal_rx_wbm_rel_info err_info; 39398c2ecf20Sopenharmony_ci struct hal_srng *srng; 39408c2ecf20Sopenharmony_ci struct sk_buff *msdu; 39418c2ecf20Sopenharmony_ci struct sk_buff_head msdu_list[MAX_RADIOS]; 39428c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb; 39438c2ecf20Sopenharmony_ci u32 *rx_desc; 39448c2ecf20Sopenharmony_ci int buf_id, mac_id; 39458c2ecf20Sopenharmony_ci int num_buffs_reaped[MAX_RADIOS] = {0}; 39468c2ecf20Sopenharmony_ci int total_num_buffs_reaped = 0; 39478c2ecf20Sopenharmony_ci int ret, i; 39488c2ecf20Sopenharmony_ci 39498c2ecf20Sopenharmony_ci for (i = 0; i < ab->num_radios; i++) 39508c2ecf20Sopenharmony_ci __skb_queue_head_init(&msdu_list[i]); 39518c2ecf20Sopenharmony_ci 39528c2ecf20Sopenharmony_ci srng = &ab->hal.srng_list[dp->rx_rel_ring.ring_id]; 39538c2ecf20Sopenharmony_ci 39548c2ecf20Sopenharmony_ci spin_lock_bh(&srng->lock); 39558c2ecf20Sopenharmony_ci 39568c2ecf20Sopenharmony_ci ath11k_hal_srng_access_begin(ab, srng); 39578c2ecf20Sopenharmony_ci 39588c2ecf20Sopenharmony_ci while (budget) { 39598c2ecf20Sopenharmony_ci rx_desc = ath11k_hal_srng_dst_get_next_entry(ab, srng); 39608c2ecf20Sopenharmony_ci if (!rx_desc) 39618c2ecf20Sopenharmony_ci break; 39628c2ecf20Sopenharmony_ci 39638c2ecf20Sopenharmony_ci ret = ath11k_hal_wbm_desc_parse_err(ab, rx_desc, &err_info); 39648c2ecf20Sopenharmony_ci if (ret) { 39658c2ecf20Sopenharmony_ci ath11k_warn(ab, 39668c2ecf20Sopenharmony_ci "failed to parse rx error in wbm_rel ring desc %d\n", 39678c2ecf20Sopenharmony_ci ret); 39688c2ecf20Sopenharmony_ci continue; 39698c2ecf20Sopenharmony_ci } 39708c2ecf20Sopenharmony_ci 39718c2ecf20Sopenharmony_ci buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, err_info.cookie); 39728c2ecf20Sopenharmony_ci mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, err_info.cookie); 39738c2ecf20Sopenharmony_ci 39748c2ecf20Sopenharmony_ci ar = ab->pdevs[mac_id].ar; 39758c2ecf20Sopenharmony_ci rx_ring = &ar->dp.rx_refill_buf_ring; 39768c2ecf20Sopenharmony_ci 39778c2ecf20Sopenharmony_ci spin_lock_bh(&rx_ring->idr_lock); 39788c2ecf20Sopenharmony_ci msdu = idr_find(&rx_ring->bufs_idr, buf_id); 39798c2ecf20Sopenharmony_ci if (!msdu) { 39808c2ecf20Sopenharmony_ci ath11k_warn(ab, "frame rx with invalid buf_id %d pdev %d\n", 39818c2ecf20Sopenharmony_ci buf_id, mac_id); 39828c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 39838c2ecf20Sopenharmony_ci continue; 39848c2ecf20Sopenharmony_ci } 39858c2ecf20Sopenharmony_ci 39868c2ecf20Sopenharmony_ci idr_remove(&rx_ring->bufs_idr, buf_id); 39878c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 39888c2ecf20Sopenharmony_ci 39898c2ecf20Sopenharmony_ci rxcb = ATH11K_SKB_RXCB(msdu); 39908c2ecf20Sopenharmony_ci dma_unmap_single(ab->dev, rxcb->paddr, 39918c2ecf20Sopenharmony_ci msdu->len + skb_tailroom(msdu), 39928c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 39938c2ecf20Sopenharmony_ci 39948c2ecf20Sopenharmony_ci num_buffs_reaped[mac_id]++; 39958c2ecf20Sopenharmony_ci total_num_buffs_reaped++; 39968c2ecf20Sopenharmony_ci budget--; 39978c2ecf20Sopenharmony_ci 39988c2ecf20Sopenharmony_ci if (err_info.push_reason != 39998c2ecf20Sopenharmony_ci HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED) { 40008c2ecf20Sopenharmony_ci dev_kfree_skb_any(msdu); 40018c2ecf20Sopenharmony_ci continue; 40028c2ecf20Sopenharmony_ci } 40038c2ecf20Sopenharmony_ci 40048c2ecf20Sopenharmony_ci rxcb->err_rel_src = err_info.err_rel_src; 40058c2ecf20Sopenharmony_ci rxcb->err_code = err_info.err_code; 40068c2ecf20Sopenharmony_ci rxcb->rx_desc = (struct hal_rx_desc *)msdu->data; 40078c2ecf20Sopenharmony_ci __skb_queue_tail(&msdu_list[mac_id], msdu); 40088c2ecf20Sopenharmony_ci } 40098c2ecf20Sopenharmony_ci 40108c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 40118c2ecf20Sopenharmony_ci 40128c2ecf20Sopenharmony_ci spin_unlock_bh(&srng->lock); 40138c2ecf20Sopenharmony_ci 40148c2ecf20Sopenharmony_ci if (!total_num_buffs_reaped) 40158c2ecf20Sopenharmony_ci goto done; 40168c2ecf20Sopenharmony_ci 40178c2ecf20Sopenharmony_ci for (i = 0; i < ab->num_radios; i++) { 40188c2ecf20Sopenharmony_ci if (!num_buffs_reaped[i]) 40198c2ecf20Sopenharmony_ci continue; 40208c2ecf20Sopenharmony_ci 40218c2ecf20Sopenharmony_ci ar = ab->pdevs[i].ar; 40228c2ecf20Sopenharmony_ci rx_ring = &ar->dp.rx_refill_buf_ring; 40238c2ecf20Sopenharmony_ci 40248c2ecf20Sopenharmony_ci ath11k_dp_rxbufs_replenish(ab, i, rx_ring, num_buffs_reaped[i], 40258c2ecf20Sopenharmony_ci HAL_RX_BUF_RBM_SW3_BM); 40268c2ecf20Sopenharmony_ci } 40278c2ecf20Sopenharmony_ci 40288c2ecf20Sopenharmony_ci rcu_read_lock(); 40298c2ecf20Sopenharmony_ci for (i = 0; i < ab->num_radios; i++) { 40308c2ecf20Sopenharmony_ci if (!rcu_dereference(ab->pdevs_active[i])) { 40318c2ecf20Sopenharmony_ci __skb_queue_purge(&msdu_list[i]); 40328c2ecf20Sopenharmony_ci continue; 40338c2ecf20Sopenharmony_ci } 40348c2ecf20Sopenharmony_ci 40358c2ecf20Sopenharmony_ci ar = ab->pdevs[i].ar; 40368c2ecf20Sopenharmony_ci 40378c2ecf20Sopenharmony_ci if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) { 40388c2ecf20Sopenharmony_ci __skb_queue_purge(&msdu_list[i]); 40398c2ecf20Sopenharmony_ci continue; 40408c2ecf20Sopenharmony_ci } 40418c2ecf20Sopenharmony_ci 40428c2ecf20Sopenharmony_ci while ((msdu = __skb_dequeue(&msdu_list[i])) != NULL) 40438c2ecf20Sopenharmony_ci ath11k_dp_rx_wbm_err(ar, napi, msdu, &msdu_list[i]); 40448c2ecf20Sopenharmony_ci } 40458c2ecf20Sopenharmony_ci rcu_read_unlock(); 40468c2ecf20Sopenharmony_cidone: 40478c2ecf20Sopenharmony_ci return total_num_buffs_reaped; 40488c2ecf20Sopenharmony_ci} 40498c2ecf20Sopenharmony_ci 40508c2ecf20Sopenharmony_ciint ath11k_dp_process_rxdma_err(struct ath11k_base *ab, int mac_id, int budget) 40518c2ecf20Sopenharmony_ci{ 40528c2ecf20Sopenharmony_ci struct ath11k *ar; 40538c2ecf20Sopenharmony_ci struct dp_srng *err_ring; 40548c2ecf20Sopenharmony_ci struct dp_rxdma_ring *rx_ring; 40558c2ecf20Sopenharmony_ci struct dp_link_desc_bank *link_desc_banks = ab->dp.link_desc_banks; 40568c2ecf20Sopenharmony_ci struct hal_srng *srng; 40578c2ecf20Sopenharmony_ci u32 msdu_cookies[HAL_NUM_RX_MSDUS_PER_LINK_DESC]; 40588c2ecf20Sopenharmony_ci enum hal_rx_buf_return_buf_manager rbm; 40598c2ecf20Sopenharmony_ci enum hal_reo_entr_rxdma_ecode rxdma_err_code; 40608c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb; 40618c2ecf20Sopenharmony_ci struct sk_buff *skb; 40628c2ecf20Sopenharmony_ci struct hal_reo_entrance_ring *entr_ring; 40638c2ecf20Sopenharmony_ci void *desc; 40648c2ecf20Sopenharmony_ci int num_buf_freed = 0; 40658c2ecf20Sopenharmony_ci int quota = budget; 40668c2ecf20Sopenharmony_ci dma_addr_t paddr; 40678c2ecf20Sopenharmony_ci u32 desc_bank; 40688c2ecf20Sopenharmony_ci void *link_desc_va; 40698c2ecf20Sopenharmony_ci int num_msdus; 40708c2ecf20Sopenharmony_ci int i; 40718c2ecf20Sopenharmony_ci int buf_id; 40728c2ecf20Sopenharmony_ci 40738c2ecf20Sopenharmony_ci ar = ab->pdevs[ath11k_hw_mac_id_to_pdev_id(&ab->hw_params, mac_id)].ar; 40748c2ecf20Sopenharmony_ci err_ring = &ar->dp.rxdma_err_dst_ring[ath11k_hw_mac_id_to_srng_id(&ab->hw_params, 40758c2ecf20Sopenharmony_ci mac_id)]; 40768c2ecf20Sopenharmony_ci rx_ring = &ar->dp.rx_refill_buf_ring; 40778c2ecf20Sopenharmony_ci 40788c2ecf20Sopenharmony_ci srng = &ab->hal.srng_list[err_ring->ring_id]; 40798c2ecf20Sopenharmony_ci 40808c2ecf20Sopenharmony_ci spin_lock_bh(&srng->lock); 40818c2ecf20Sopenharmony_ci 40828c2ecf20Sopenharmony_ci ath11k_hal_srng_access_begin(ab, srng); 40838c2ecf20Sopenharmony_ci 40848c2ecf20Sopenharmony_ci while (quota-- && 40858c2ecf20Sopenharmony_ci (desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) { 40868c2ecf20Sopenharmony_ci ath11k_hal_rx_reo_ent_paddr_get(ab, desc, &paddr, &desc_bank); 40878c2ecf20Sopenharmony_ci 40888c2ecf20Sopenharmony_ci entr_ring = (struct hal_reo_entrance_ring *)desc; 40898c2ecf20Sopenharmony_ci rxdma_err_code = 40908c2ecf20Sopenharmony_ci FIELD_GET(HAL_REO_ENTR_RING_INFO1_RXDMA_ERROR_CODE, 40918c2ecf20Sopenharmony_ci entr_ring->info1); 40928c2ecf20Sopenharmony_ci ab->soc_stats.rxdma_error[rxdma_err_code]++; 40938c2ecf20Sopenharmony_ci 40948c2ecf20Sopenharmony_ci link_desc_va = link_desc_banks[desc_bank].vaddr + 40958c2ecf20Sopenharmony_ci (paddr - link_desc_banks[desc_bank].paddr); 40968c2ecf20Sopenharmony_ci ath11k_hal_rx_msdu_link_info_get(link_desc_va, &num_msdus, 40978c2ecf20Sopenharmony_ci msdu_cookies, &rbm); 40988c2ecf20Sopenharmony_ci 40998c2ecf20Sopenharmony_ci for (i = 0; i < num_msdus; i++) { 41008c2ecf20Sopenharmony_ci buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, 41018c2ecf20Sopenharmony_ci msdu_cookies[i]); 41028c2ecf20Sopenharmony_ci 41038c2ecf20Sopenharmony_ci spin_lock_bh(&rx_ring->idr_lock); 41048c2ecf20Sopenharmony_ci skb = idr_find(&rx_ring->bufs_idr, buf_id); 41058c2ecf20Sopenharmony_ci if (!skb) { 41068c2ecf20Sopenharmony_ci ath11k_warn(ab, "rxdma error with invalid buf_id %d\n", 41078c2ecf20Sopenharmony_ci buf_id); 41088c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 41098c2ecf20Sopenharmony_ci continue; 41108c2ecf20Sopenharmony_ci } 41118c2ecf20Sopenharmony_ci 41128c2ecf20Sopenharmony_ci idr_remove(&rx_ring->bufs_idr, buf_id); 41138c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 41148c2ecf20Sopenharmony_ci 41158c2ecf20Sopenharmony_ci rxcb = ATH11K_SKB_RXCB(skb); 41168c2ecf20Sopenharmony_ci dma_unmap_single(ab->dev, rxcb->paddr, 41178c2ecf20Sopenharmony_ci skb->len + skb_tailroom(skb), 41188c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 41198c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 41208c2ecf20Sopenharmony_ci 41218c2ecf20Sopenharmony_ci num_buf_freed++; 41228c2ecf20Sopenharmony_ci } 41238c2ecf20Sopenharmony_ci 41248c2ecf20Sopenharmony_ci ath11k_dp_rx_link_desc_return(ab, desc, 41258c2ecf20Sopenharmony_ci HAL_WBM_REL_BM_ACT_PUT_IN_IDLE); 41268c2ecf20Sopenharmony_ci } 41278c2ecf20Sopenharmony_ci 41288c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 41298c2ecf20Sopenharmony_ci 41308c2ecf20Sopenharmony_ci spin_unlock_bh(&srng->lock); 41318c2ecf20Sopenharmony_ci 41328c2ecf20Sopenharmony_ci if (num_buf_freed) 41338c2ecf20Sopenharmony_ci ath11k_dp_rxbufs_replenish(ab, mac_id, rx_ring, num_buf_freed, 41348c2ecf20Sopenharmony_ci HAL_RX_BUF_RBM_SW3_BM); 41358c2ecf20Sopenharmony_ci 41368c2ecf20Sopenharmony_ci return budget - quota; 41378c2ecf20Sopenharmony_ci} 41388c2ecf20Sopenharmony_ci 41398c2ecf20Sopenharmony_civoid ath11k_dp_process_reo_status(struct ath11k_base *ab) 41408c2ecf20Sopenharmony_ci{ 41418c2ecf20Sopenharmony_ci struct ath11k_dp *dp = &ab->dp; 41428c2ecf20Sopenharmony_ci struct hal_srng *srng; 41438c2ecf20Sopenharmony_ci struct dp_reo_cmd *cmd, *tmp; 41448c2ecf20Sopenharmony_ci bool found = false; 41458c2ecf20Sopenharmony_ci u32 *reo_desc; 41468c2ecf20Sopenharmony_ci u16 tag; 41478c2ecf20Sopenharmony_ci struct hal_reo_status reo_status; 41488c2ecf20Sopenharmony_ci 41498c2ecf20Sopenharmony_ci srng = &ab->hal.srng_list[dp->reo_status_ring.ring_id]; 41508c2ecf20Sopenharmony_ci 41518c2ecf20Sopenharmony_ci memset(&reo_status, 0, sizeof(reo_status)); 41528c2ecf20Sopenharmony_ci 41538c2ecf20Sopenharmony_ci spin_lock_bh(&srng->lock); 41548c2ecf20Sopenharmony_ci 41558c2ecf20Sopenharmony_ci ath11k_hal_srng_access_begin(ab, srng); 41568c2ecf20Sopenharmony_ci 41578c2ecf20Sopenharmony_ci while ((reo_desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) { 41588c2ecf20Sopenharmony_ci tag = FIELD_GET(HAL_SRNG_TLV_HDR_TAG, *reo_desc); 41598c2ecf20Sopenharmony_ci 41608c2ecf20Sopenharmony_ci switch (tag) { 41618c2ecf20Sopenharmony_ci case HAL_REO_GET_QUEUE_STATS_STATUS: 41628c2ecf20Sopenharmony_ci ath11k_hal_reo_status_queue_stats(ab, reo_desc, 41638c2ecf20Sopenharmony_ci &reo_status); 41648c2ecf20Sopenharmony_ci break; 41658c2ecf20Sopenharmony_ci case HAL_REO_FLUSH_QUEUE_STATUS: 41668c2ecf20Sopenharmony_ci ath11k_hal_reo_flush_queue_status(ab, reo_desc, 41678c2ecf20Sopenharmony_ci &reo_status); 41688c2ecf20Sopenharmony_ci break; 41698c2ecf20Sopenharmony_ci case HAL_REO_FLUSH_CACHE_STATUS: 41708c2ecf20Sopenharmony_ci ath11k_hal_reo_flush_cache_status(ab, reo_desc, 41718c2ecf20Sopenharmony_ci &reo_status); 41728c2ecf20Sopenharmony_ci break; 41738c2ecf20Sopenharmony_ci case HAL_REO_UNBLOCK_CACHE_STATUS: 41748c2ecf20Sopenharmony_ci ath11k_hal_reo_unblk_cache_status(ab, reo_desc, 41758c2ecf20Sopenharmony_ci &reo_status); 41768c2ecf20Sopenharmony_ci break; 41778c2ecf20Sopenharmony_ci case HAL_REO_FLUSH_TIMEOUT_LIST_STATUS: 41788c2ecf20Sopenharmony_ci ath11k_hal_reo_flush_timeout_list_status(ab, reo_desc, 41798c2ecf20Sopenharmony_ci &reo_status); 41808c2ecf20Sopenharmony_ci break; 41818c2ecf20Sopenharmony_ci case HAL_REO_DESCRIPTOR_THRESHOLD_REACHED_STATUS: 41828c2ecf20Sopenharmony_ci ath11k_hal_reo_desc_thresh_reached_status(ab, reo_desc, 41838c2ecf20Sopenharmony_ci &reo_status); 41848c2ecf20Sopenharmony_ci break; 41858c2ecf20Sopenharmony_ci case HAL_REO_UPDATE_RX_REO_QUEUE_STATUS: 41868c2ecf20Sopenharmony_ci ath11k_hal_reo_update_rx_reo_queue_status(ab, reo_desc, 41878c2ecf20Sopenharmony_ci &reo_status); 41888c2ecf20Sopenharmony_ci break; 41898c2ecf20Sopenharmony_ci default: 41908c2ecf20Sopenharmony_ci ath11k_warn(ab, "Unknown reo status type %d\n", tag); 41918c2ecf20Sopenharmony_ci continue; 41928c2ecf20Sopenharmony_ci } 41938c2ecf20Sopenharmony_ci 41948c2ecf20Sopenharmony_ci spin_lock_bh(&dp->reo_cmd_lock); 41958c2ecf20Sopenharmony_ci list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) { 41968c2ecf20Sopenharmony_ci if (reo_status.uniform_hdr.cmd_num == cmd->cmd_num) { 41978c2ecf20Sopenharmony_ci found = true; 41988c2ecf20Sopenharmony_ci list_del(&cmd->list); 41998c2ecf20Sopenharmony_ci break; 42008c2ecf20Sopenharmony_ci } 42018c2ecf20Sopenharmony_ci } 42028c2ecf20Sopenharmony_ci spin_unlock_bh(&dp->reo_cmd_lock); 42038c2ecf20Sopenharmony_ci 42048c2ecf20Sopenharmony_ci if (found) { 42058c2ecf20Sopenharmony_ci cmd->handler(dp, (void *)&cmd->data, 42068c2ecf20Sopenharmony_ci reo_status.uniform_hdr.cmd_status); 42078c2ecf20Sopenharmony_ci kfree(cmd); 42088c2ecf20Sopenharmony_ci } 42098c2ecf20Sopenharmony_ci 42108c2ecf20Sopenharmony_ci found = false; 42118c2ecf20Sopenharmony_ci } 42128c2ecf20Sopenharmony_ci 42138c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 42148c2ecf20Sopenharmony_ci 42158c2ecf20Sopenharmony_ci spin_unlock_bh(&srng->lock); 42168c2ecf20Sopenharmony_ci} 42178c2ecf20Sopenharmony_ci 42188c2ecf20Sopenharmony_civoid ath11k_dp_rx_pdev_free(struct ath11k_base *ab, int mac_id) 42198c2ecf20Sopenharmony_ci{ 42208c2ecf20Sopenharmony_ci struct ath11k *ar = ab->pdevs[mac_id].ar; 42218c2ecf20Sopenharmony_ci 42228c2ecf20Sopenharmony_ci ath11k_dp_rx_pdev_srng_free(ar); 42238c2ecf20Sopenharmony_ci ath11k_dp_rxdma_pdev_buf_free(ar); 42248c2ecf20Sopenharmony_ci} 42258c2ecf20Sopenharmony_ci 42268c2ecf20Sopenharmony_ciint ath11k_dp_rx_pdev_alloc(struct ath11k_base *ab, int mac_id) 42278c2ecf20Sopenharmony_ci{ 42288c2ecf20Sopenharmony_ci struct ath11k *ar = ab->pdevs[mac_id].ar; 42298c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp = &ar->dp; 42308c2ecf20Sopenharmony_ci u32 ring_id; 42318c2ecf20Sopenharmony_ci int i; 42328c2ecf20Sopenharmony_ci int ret; 42338c2ecf20Sopenharmony_ci 42348c2ecf20Sopenharmony_ci ret = ath11k_dp_rx_pdev_srng_alloc(ar); 42358c2ecf20Sopenharmony_ci if (ret) { 42368c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to setup rx srngs\n"); 42378c2ecf20Sopenharmony_ci return ret; 42388c2ecf20Sopenharmony_ci } 42398c2ecf20Sopenharmony_ci 42408c2ecf20Sopenharmony_ci ret = ath11k_dp_rxdma_pdev_buf_setup(ar); 42418c2ecf20Sopenharmony_ci if (ret) { 42428c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to setup rxdma ring\n"); 42438c2ecf20Sopenharmony_ci return ret; 42448c2ecf20Sopenharmony_ci } 42458c2ecf20Sopenharmony_ci 42468c2ecf20Sopenharmony_ci ring_id = dp->rx_refill_buf_ring.refill_buf_ring.ring_id; 42478c2ecf20Sopenharmony_ci ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id, HAL_RXDMA_BUF); 42488c2ecf20Sopenharmony_ci if (ret) { 42498c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to configure rx_refill_buf_ring %d\n", 42508c2ecf20Sopenharmony_ci ret); 42518c2ecf20Sopenharmony_ci return ret; 42528c2ecf20Sopenharmony_ci } 42538c2ecf20Sopenharmony_ci 42548c2ecf20Sopenharmony_ci if (ab->hw_params.rx_mac_buf_ring) { 42558c2ecf20Sopenharmony_ci for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { 42568c2ecf20Sopenharmony_ci ring_id = dp->rx_mac_buf_ring[i].ring_id; 42578c2ecf20Sopenharmony_ci ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, 42588c2ecf20Sopenharmony_ci mac_id + i, HAL_RXDMA_BUF); 42598c2ecf20Sopenharmony_ci if (ret) { 42608c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to configure rx_mac_buf_ring%d %d\n", 42618c2ecf20Sopenharmony_ci i, ret); 42628c2ecf20Sopenharmony_ci return ret; 42638c2ecf20Sopenharmony_ci } 42648c2ecf20Sopenharmony_ci } 42658c2ecf20Sopenharmony_ci } 42668c2ecf20Sopenharmony_ci 42678c2ecf20Sopenharmony_ci for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { 42688c2ecf20Sopenharmony_ci ring_id = dp->rxdma_err_dst_ring[i].ring_id; 42698c2ecf20Sopenharmony_ci ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, 42708c2ecf20Sopenharmony_ci mac_id + i, HAL_RXDMA_DST); 42718c2ecf20Sopenharmony_ci if (ret) { 42728c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to configure rxdma_err_dest_ring%d %d\n", 42738c2ecf20Sopenharmony_ci i, ret); 42748c2ecf20Sopenharmony_ci return ret; 42758c2ecf20Sopenharmony_ci } 42768c2ecf20Sopenharmony_ci } 42778c2ecf20Sopenharmony_ci 42788c2ecf20Sopenharmony_ci if (!ab->hw_params.rxdma1_enable) 42798c2ecf20Sopenharmony_ci goto config_refill_ring; 42808c2ecf20Sopenharmony_ci 42818c2ecf20Sopenharmony_ci ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id; 42828c2ecf20Sopenharmony_ci ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, 42838c2ecf20Sopenharmony_ci mac_id, HAL_RXDMA_MONITOR_BUF); 42848c2ecf20Sopenharmony_ci if (ret) { 42858c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to configure rxdma_mon_buf_ring %d\n", 42868c2ecf20Sopenharmony_ci ret); 42878c2ecf20Sopenharmony_ci return ret; 42888c2ecf20Sopenharmony_ci } 42898c2ecf20Sopenharmony_ci ret = ath11k_dp_tx_htt_srng_setup(ab, 42908c2ecf20Sopenharmony_ci dp->rxdma_mon_dst_ring.ring_id, 42918c2ecf20Sopenharmony_ci mac_id, HAL_RXDMA_MONITOR_DST); 42928c2ecf20Sopenharmony_ci if (ret) { 42938c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to configure rxdma_mon_dst_ring %d\n", 42948c2ecf20Sopenharmony_ci ret); 42958c2ecf20Sopenharmony_ci return ret; 42968c2ecf20Sopenharmony_ci } 42978c2ecf20Sopenharmony_ci ret = ath11k_dp_tx_htt_srng_setup(ab, 42988c2ecf20Sopenharmony_ci dp->rxdma_mon_desc_ring.ring_id, 42998c2ecf20Sopenharmony_ci mac_id, HAL_RXDMA_MONITOR_DESC); 43008c2ecf20Sopenharmony_ci if (ret) { 43018c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to configure rxdma_mon_dst_ring %d\n", 43028c2ecf20Sopenharmony_ci ret); 43038c2ecf20Sopenharmony_ci return ret; 43048c2ecf20Sopenharmony_ci } 43058c2ecf20Sopenharmony_ci 43068c2ecf20Sopenharmony_ciconfig_refill_ring: 43078c2ecf20Sopenharmony_ci for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { 43088c2ecf20Sopenharmony_ci ring_id = dp->rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; 43098c2ecf20Sopenharmony_ci ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id + i, 43108c2ecf20Sopenharmony_ci HAL_RXDMA_MONITOR_STATUS); 43118c2ecf20Sopenharmony_ci if (ret) { 43128c2ecf20Sopenharmony_ci ath11k_warn(ab, 43138c2ecf20Sopenharmony_ci "failed to configure mon_status_refill_ring%d %d\n", 43148c2ecf20Sopenharmony_ci i, ret); 43158c2ecf20Sopenharmony_ci return ret; 43168c2ecf20Sopenharmony_ci } 43178c2ecf20Sopenharmony_ci } 43188c2ecf20Sopenharmony_ci 43198c2ecf20Sopenharmony_ci return 0; 43208c2ecf20Sopenharmony_ci} 43218c2ecf20Sopenharmony_ci 43228c2ecf20Sopenharmony_cistatic void ath11k_dp_mon_set_frag_len(u32 *total_len, u32 *frag_len) 43238c2ecf20Sopenharmony_ci{ 43248c2ecf20Sopenharmony_ci if (*total_len >= (DP_RX_BUFFER_SIZE - sizeof(struct hal_rx_desc))) { 43258c2ecf20Sopenharmony_ci *frag_len = DP_RX_BUFFER_SIZE - sizeof(struct hal_rx_desc); 43268c2ecf20Sopenharmony_ci *total_len -= *frag_len; 43278c2ecf20Sopenharmony_ci } else { 43288c2ecf20Sopenharmony_ci *frag_len = *total_len; 43298c2ecf20Sopenharmony_ci *total_len = 0; 43308c2ecf20Sopenharmony_ci } 43318c2ecf20Sopenharmony_ci} 43328c2ecf20Sopenharmony_ci 43338c2ecf20Sopenharmony_cistatic 43348c2ecf20Sopenharmony_ciint ath11k_dp_rx_monitor_link_desc_return(struct ath11k *ar, 43358c2ecf20Sopenharmony_ci void *p_last_buf_addr_info, 43368c2ecf20Sopenharmony_ci u8 mac_id) 43378c2ecf20Sopenharmony_ci{ 43388c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp = &ar->dp; 43398c2ecf20Sopenharmony_ci struct dp_srng *dp_srng; 43408c2ecf20Sopenharmony_ci void *hal_srng; 43418c2ecf20Sopenharmony_ci void *src_srng_desc; 43428c2ecf20Sopenharmony_ci int ret = 0; 43438c2ecf20Sopenharmony_ci 43448c2ecf20Sopenharmony_ci if (ar->ab->hw_params.rxdma1_enable) { 43458c2ecf20Sopenharmony_ci dp_srng = &dp->rxdma_mon_desc_ring; 43468c2ecf20Sopenharmony_ci hal_srng = &ar->ab->hal.srng_list[dp_srng->ring_id]; 43478c2ecf20Sopenharmony_ci } else { 43488c2ecf20Sopenharmony_ci dp_srng = &ar->ab->dp.wbm_desc_rel_ring; 43498c2ecf20Sopenharmony_ci hal_srng = &ar->ab->hal.srng_list[dp_srng->ring_id]; 43508c2ecf20Sopenharmony_ci } 43518c2ecf20Sopenharmony_ci 43528c2ecf20Sopenharmony_ci ath11k_hal_srng_access_begin(ar->ab, hal_srng); 43538c2ecf20Sopenharmony_ci 43548c2ecf20Sopenharmony_ci src_srng_desc = ath11k_hal_srng_src_get_next_entry(ar->ab, hal_srng); 43558c2ecf20Sopenharmony_ci 43568c2ecf20Sopenharmony_ci if (src_srng_desc) { 43578c2ecf20Sopenharmony_ci struct ath11k_buffer_addr *src_desc = 43588c2ecf20Sopenharmony_ci (struct ath11k_buffer_addr *)src_srng_desc; 43598c2ecf20Sopenharmony_ci 43608c2ecf20Sopenharmony_ci *src_desc = *((struct ath11k_buffer_addr *)p_last_buf_addr_info); 43618c2ecf20Sopenharmony_ci } else { 43628c2ecf20Sopenharmony_ci ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 43638c2ecf20Sopenharmony_ci "Monitor Link Desc Ring %d Full", mac_id); 43648c2ecf20Sopenharmony_ci ret = -ENOMEM; 43658c2ecf20Sopenharmony_ci } 43668c2ecf20Sopenharmony_ci 43678c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ar->ab, hal_srng); 43688c2ecf20Sopenharmony_ci return ret; 43698c2ecf20Sopenharmony_ci} 43708c2ecf20Sopenharmony_ci 43718c2ecf20Sopenharmony_cistatic 43728c2ecf20Sopenharmony_civoid ath11k_dp_rx_mon_next_link_desc_get(void *rx_msdu_link_desc, 43738c2ecf20Sopenharmony_ci dma_addr_t *paddr, u32 *sw_cookie, 43748c2ecf20Sopenharmony_ci u8 *rbm, 43758c2ecf20Sopenharmony_ci void **pp_buf_addr_info) 43768c2ecf20Sopenharmony_ci{ 43778c2ecf20Sopenharmony_ci struct hal_rx_msdu_link *msdu_link = 43788c2ecf20Sopenharmony_ci (struct hal_rx_msdu_link *)rx_msdu_link_desc; 43798c2ecf20Sopenharmony_ci struct ath11k_buffer_addr *buf_addr_info; 43808c2ecf20Sopenharmony_ci 43818c2ecf20Sopenharmony_ci buf_addr_info = (struct ath11k_buffer_addr *)&msdu_link->buf_addr_info; 43828c2ecf20Sopenharmony_ci 43838c2ecf20Sopenharmony_ci ath11k_hal_rx_buf_addr_info_get(buf_addr_info, paddr, sw_cookie, rbm); 43848c2ecf20Sopenharmony_ci 43858c2ecf20Sopenharmony_ci *pp_buf_addr_info = (void *)buf_addr_info; 43868c2ecf20Sopenharmony_ci} 43878c2ecf20Sopenharmony_ci 43888c2ecf20Sopenharmony_cistatic int ath11k_dp_pkt_set_pktlen(struct sk_buff *skb, u32 len) 43898c2ecf20Sopenharmony_ci{ 43908c2ecf20Sopenharmony_ci if (skb->len > len) { 43918c2ecf20Sopenharmony_ci skb_trim(skb, len); 43928c2ecf20Sopenharmony_ci } else { 43938c2ecf20Sopenharmony_ci if (skb_tailroom(skb) < len - skb->len) { 43948c2ecf20Sopenharmony_ci if ((pskb_expand_head(skb, 0, 43958c2ecf20Sopenharmony_ci len - skb->len - skb_tailroom(skb), 43968c2ecf20Sopenharmony_ci GFP_ATOMIC))) { 43978c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 43988c2ecf20Sopenharmony_ci return -ENOMEM; 43998c2ecf20Sopenharmony_ci } 44008c2ecf20Sopenharmony_ci } 44018c2ecf20Sopenharmony_ci skb_put(skb, (len - skb->len)); 44028c2ecf20Sopenharmony_ci } 44038c2ecf20Sopenharmony_ci return 0; 44048c2ecf20Sopenharmony_ci} 44058c2ecf20Sopenharmony_ci 44068c2ecf20Sopenharmony_cistatic void ath11k_hal_rx_msdu_list_get(struct ath11k *ar, 44078c2ecf20Sopenharmony_ci void *msdu_link_desc, 44088c2ecf20Sopenharmony_ci struct hal_rx_msdu_list *msdu_list, 44098c2ecf20Sopenharmony_ci u16 *num_msdus) 44108c2ecf20Sopenharmony_ci{ 44118c2ecf20Sopenharmony_ci struct hal_rx_msdu_details *msdu_details = NULL; 44128c2ecf20Sopenharmony_ci struct rx_msdu_desc *msdu_desc_info = NULL; 44138c2ecf20Sopenharmony_ci struct hal_rx_msdu_link *msdu_link = NULL; 44148c2ecf20Sopenharmony_ci int i; 44158c2ecf20Sopenharmony_ci u32 last = FIELD_PREP(RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU, 1); 44168c2ecf20Sopenharmony_ci u32 first = FIELD_PREP(RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU, 1); 44178c2ecf20Sopenharmony_ci u8 tmp = 0; 44188c2ecf20Sopenharmony_ci 44198c2ecf20Sopenharmony_ci msdu_link = (struct hal_rx_msdu_link *)msdu_link_desc; 44208c2ecf20Sopenharmony_ci msdu_details = &msdu_link->msdu_link[0]; 44218c2ecf20Sopenharmony_ci 44228c2ecf20Sopenharmony_ci for (i = 0; i < HAL_RX_NUM_MSDU_DESC; i++) { 44238c2ecf20Sopenharmony_ci if (FIELD_GET(BUFFER_ADDR_INFO0_ADDR, 44248c2ecf20Sopenharmony_ci msdu_details[i].buf_addr_info.info0) == 0) { 44258c2ecf20Sopenharmony_ci msdu_desc_info = &msdu_details[i - 1].rx_msdu_info; 44268c2ecf20Sopenharmony_ci msdu_desc_info->info0 |= last; 44278c2ecf20Sopenharmony_ci ; 44288c2ecf20Sopenharmony_ci break; 44298c2ecf20Sopenharmony_ci } 44308c2ecf20Sopenharmony_ci msdu_desc_info = &msdu_details[i].rx_msdu_info; 44318c2ecf20Sopenharmony_ci 44328c2ecf20Sopenharmony_ci if (!i) 44338c2ecf20Sopenharmony_ci msdu_desc_info->info0 |= first; 44348c2ecf20Sopenharmony_ci else if (i == (HAL_RX_NUM_MSDU_DESC - 1)) 44358c2ecf20Sopenharmony_ci msdu_desc_info->info0 |= last; 44368c2ecf20Sopenharmony_ci msdu_list->msdu_info[i].msdu_flags = msdu_desc_info->info0; 44378c2ecf20Sopenharmony_ci msdu_list->msdu_info[i].msdu_len = 44388c2ecf20Sopenharmony_ci HAL_RX_MSDU_PKT_LENGTH_GET(msdu_desc_info->info0); 44398c2ecf20Sopenharmony_ci msdu_list->sw_cookie[i] = 44408c2ecf20Sopenharmony_ci FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, 44418c2ecf20Sopenharmony_ci msdu_details[i].buf_addr_info.info1); 44428c2ecf20Sopenharmony_ci tmp = FIELD_GET(BUFFER_ADDR_INFO1_RET_BUF_MGR, 44438c2ecf20Sopenharmony_ci msdu_details[i].buf_addr_info.info1); 44448c2ecf20Sopenharmony_ci msdu_list->rbm[i] = tmp; 44458c2ecf20Sopenharmony_ci } 44468c2ecf20Sopenharmony_ci *num_msdus = i; 44478c2ecf20Sopenharmony_ci} 44488c2ecf20Sopenharmony_ci 44498c2ecf20Sopenharmony_cistatic u32 ath11k_dp_rx_mon_comp_ppduid(u32 msdu_ppdu_id, u32 *ppdu_id, 44508c2ecf20Sopenharmony_ci u32 *rx_bufs_used) 44518c2ecf20Sopenharmony_ci{ 44528c2ecf20Sopenharmony_ci u32 ret = 0; 44538c2ecf20Sopenharmony_ci 44548c2ecf20Sopenharmony_ci if ((*ppdu_id < msdu_ppdu_id) && 44558c2ecf20Sopenharmony_ci ((msdu_ppdu_id - *ppdu_id) < DP_NOT_PPDU_ID_WRAP_AROUND)) { 44568c2ecf20Sopenharmony_ci *ppdu_id = msdu_ppdu_id; 44578c2ecf20Sopenharmony_ci ret = msdu_ppdu_id; 44588c2ecf20Sopenharmony_ci } else if ((*ppdu_id > msdu_ppdu_id) && 44598c2ecf20Sopenharmony_ci ((*ppdu_id - msdu_ppdu_id) > DP_NOT_PPDU_ID_WRAP_AROUND)) { 44608c2ecf20Sopenharmony_ci /* mon_dst is behind than mon_status 44618c2ecf20Sopenharmony_ci * skip dst_ring and free it 44628c2ecf20Sopenharmony_ci */ 44638c2ecf20Sopenharmony_ci *rx_bufs_used += 1; 44648c2ecf20Sopenharmony_ci *ppdu_id = msdu_ppdu_id; 44658c2ecf20Sopenharmony_ci ret = msdu_ppdu_id; 44668c2ecf20Sopenharmony_ci } 44678c2ecf20Sopenharmony_ci return ret; 44688c2ecf20Sopenharmony_ci} 44698c2ecf20Sopenharmony_ci 44708c2ecf20Sopenharmony_cistatic void ath11k_dp_mon_get_buf_len(struct hal_rx_msdu_desc_info *info, 44718c2ecf20Sopenharmony_ci bool *is_frag, u32 *total_len, 44728c2ecf20Sopenharmony_ci u32 *frag_len, u32 *msdu_cnt) 44738c2ecf20Sopenharmony_ci{ 44748c2ecf20Sopenharmony_ci if (info->msdu_flags & RX_MSDU_DESC_INFO0_MSDU_CONTINUATION) { 44758c2ecf20Sopenharmony_ci if (!*is_frag) { 44768c2ecf20Sopenharmony_ci *total_len = info->msdu_len; 44778c2ecf20Sopenharmony_ci *is_frag = true; 44788c2ecf20Sopenharmony_ci } 44798c2ecf20Sopenharmony_ci ath11k_dp_mon_set_frag_len(total_len, 44808c2ecf20Sopenharmony_ci frag_len); 44818c2ecf20Sopenharmony_ci } else { 44828c2ecf20Sopenharmony_ci if (*is_frag) { 44838c2ecf20Sopenharmony_ci ath11k_dp_mon_set_frag_len(total_len, 44848c2ecf20Sopenharmony_ci frag_len); 44858c2ecf20Sopenharmony_ci } else { 44868c2ecf20Sopenharmony_ci *frag_len = info->msdu_len; 44878c2ecf20Sopenharmony_ci } 44888c2ecf20Sopenharmony_ci *is_frag = false; 44898c2ecf20Sopenharmony_ci *msdu_cnt -= 1; 44908c2ecf20Sopenharmony_ci } 44918c2ecf20Sopenharmony_ci} 44928c2ecf20Sopenharmony_ci 44938c2ecf20Sopenharmony_cistatic u32 44948c2ecf20Sopenharmony_ciath11k_dp_rx_mon_mpdu_pop(struct ath11k *ar, int mac_id, 44958c2ecf20Sopenharmony_ci void *ring_entry, struct sk_buff **head_msdu, 44968c2ecf20Sopenharmony_ci struct sk_buff **tail_msdu, u32 *npackets, 44978c2ecf20Sopenharmony_ci u32 *ppdu_id) 44988c2ecf20Sopenharmony_ci{ 44998c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp = &ar->dp; 45008c2ecf20Sopenharmony_ci struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data; 45018c2ecf20Sopenharmony_ci struct dp_rxdma_ring *rx_ring = &dp->rxdma_mon_buf_ring; 45028c2ecf20Sopenharmony_ci struct sk_buff *msdu = NULL, *last = NULL; 45038c2ecf20Sopenharmony_ci struct hal_rx_msdu_list msdu_list; 45048c2ecf20Sopenharmony_ci void *p_buf_addr_info, *p_last_buf_addr_info; 45058c2ecf20Sopenharmony_ci struct hal_rx_desc *rx_desc; 45068c2ecf20Sopenharmony_ci void *rx_msdu_link_desc; 45078c2ecf20Sopenharmony_ci dma_addr_t paddr; 45088c2ecf20Sopenharmony_ci u16 num_msdus = 0; 45098c2ecf20Sopenharmony_ci u32 rx_buf_size, rx_pkt_offset, sw_cookie; 45108c2ecf20Sopenharmony_ci u32 rx_bufs_used = 0, i = 0; 45118c2ecf20Sopenharmony_ci u32 msdu_ppdu_id = 0, msdu_cnt = 0; 45128c2ecf20Sopenharmony_ci u32 total_len = 0, frag_len = 0; 45138c2ecf20Sopenharmony_ci bool is_frag, is_first_msdu; 45148c2ecf20Sopenharmony_ci bool drop_mpdu = false; 45158c2ecf20Sopenharmony_ci struct ath11k_skb_rxcb *rxcb; 45168c2ecf20Sopenharmony_ci struct hal_reo_entrance_ring *ent_desc = 45178c2ecf20Sopenharmony_ci (struct hal_reo_entrance_ring *)ring_entry; 45188c2ecf20Sopenharmony_ci int buf_id; 45198c2ecf20Sopenharmony_ci u32 rx_link_buf_info[2]; 45208c2ecf20Sopenharmony_ci u8 rbm; 45218c2ecf20Sopenharmony_ci 45228c2ecf20Sopenharmony_ci if (!ar->ab->hw_params.rxdma1_enable) 45238c2ecf20Sopenharmony_ci rx_ring = &dp->rx_refill_buf_ring; 45248c2ecf20Sopenharmony_ci 45258c2ecf20Sopenharmony_ci ath11k_hal_rx_reo_ent_buf_paddr_get(ring_entry, &paddr, 45268c2ecf20Sopenharmony_ci &sw_cookie, 45278c2ecf20Sopenharmony_ci &p_last_buf_addr_info, &rbm, 45288c2ecf20Sopenharmony_ci &msdu_cnt); 45298c2ecf20Sopenharmony_ci 45308c2ecf20Sopenharmony_ci if (FIELD_GET(HAL_REO_ENTR_RING_INFO1_RXDMA_PUSH_REASON, 45318c2ecf20Sopenharmony_ci ent_desc->info1) == 45328c2ecf20Sopenharmony_ci HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED) { 45338c2ecf20Sopenharmony_ci u8 rxdma_err = 45348c2ecf20Sopenharmony_ci FIELD_GET(HAL_REO_ENTR_RING_INFO1_RXDMA_ERROR_CODE, 45358c2ecf20Sopenharmony_ci ent_desc->info1); 45368c2ecf20Sopenharmony_ci if (rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_FLUSH_REQUEST_ERR || 45378c2ecf20Sopenharmony_ci rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_MPDU_LEN_ERR || 45388c2ecf20Sopenharmony_ci rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_OVERFLOW_ERR) { 45398c2ecf20Sopenharmony_ci drop_mpdu = true; 45408c2ecf20Sopenharmony_ci pmon->rx_mon_stats.dest_mpdu_drop++; 45418c2ecf20Sopenharmony_ci } 45428c2ecf20Sopenharmony_ci } 45438c2ecf20Sopenharmony_ci 45448c2ecf20Sopenharmony_ci is_frag = false; 45458c2ecf20Sopenharmony_ci is_first_msdu = true; 45468c2ecf20Sopenharmony_ci 45478c2ecf20Sopenharmony_ci do { 45488c2ecf20Sopenharmony_ci if (pmon->mon_last_linkdesc_paddr == paddr) { 45498c2ecf20Sopenharmony_ci pmon->rx_mon_stats.dup_mon_linkdesc_cnt++; 45508c2ecf20Sopenharmony_ci return rx_bufs_used; 45518c2ecf20Sopenharmony_ci } 45528c2ecf20Sopenharmony_ci 45538c2ecf20Sopenharmony_ci if (ar->ab->hw_params.rxdma1_enable) 45548c2ecf20Sopenharmony_ci rx_msdu_link_desc = 45558c2ecf20Sopenharmony_ci (void *)pmon->link_desc_banks[sw_cookie].vaddr + 45568c2ecf20Sopenharmony_ci (paddr - pmon->link_desc_banks[sw_cookie].paddr); 45578c2ecf20Sopenharmony_ci else 45588c2ecf20Sopenharmony_ci rx_msdu_link_desc = 45598c2ecf20Sopenharmony_ci (void *)ar->ab->dp.link_desc_banks[sw_cookie].vaddr + 45608c2ecf20Sopenharmony_ci (paddr - ar->ab->dp.link_desc_banks[sw_cookie].paddr); 45618c2ecf20Sopenharmony_ci 45628c2ecf20Sopenharmony_ci ath11k_hal_rx_msdu_list_get(ar, rx_msdu_link_desc, &msdu_list, 45638c2ecf20Sopenharmony_ci &num_msdus); 45648c2ecf20Sopenharmony_ci 45658c2ecf20Sopenharmony_ci for (i = 0; i < num_msdus; i++) { 45668c2ecf20Sopenharmony_ci u32 l2_hdr_offset; 45678c2ecf20Sopenharmony_ci 45688c2ecf20Sopenharmony_ci if (pmon->mon_last_buf_cookie == msdu_list.sw_cookie[i]) { 45698c2ecf20Sopenharmony_ci ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 45708c2ecf20Sopenharmony_ci "i %d last_cookie %d is same\n", 45718c2ecf20Sopenharmony_ci i, pmon->mon_last_buf_cookie); 45728c2ecf20Sopenharmony_ci drop_mpdu = true; 45738c2ecf20Sopenharmony_ci pmon->rx_mon_stats.dup_mon_buf_cnt++; 45748c2ecf20Sopenharmony_ci continue; 45758c2ecf20Sopenharmony_ci } 45768c2ecf20Sopenharmony_ci buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, 45778c2ecf20Sopenharmony_ci msdu_list.sw_cookie[i]); 45788c2ecf20Sopenharmony_ci 45798c2ecf20Sopenharmony_ci spin_lock_bh(&rx_ring->idr_lock); 45808c2ecf20Sopenharmony_ci msdu = idr_find(&rx_ring->bufs_idr, buf_id); 45818c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 45828c2ecf20Sopenharmony_ci if (!msdu) { 45838c2ecf20Sopenharmony_ci ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 45848c2ecf20Sopenharmony_ci "msdu_pop: invalid buf_id %d\n", buf_id); 45858c2ecf20Sopenharmony_ci break; 45868c2ecf20Sopenharmony_ci } 45878c2ecf20Sopenharmony_ci rxcb = ATH11K_SKB_RXCB(msdu); 45888c2ecf20Sopenharmony_ci if (!rxcb->unmapped) { 45898c2ecf20Sopenharmony_ci dma_unmap_single(ar->ab->dev, rxcb->paddr, 45908c2ecf20Sopenharmony_ci msdu->len + 45918c2ecf20Sopenharmony_ci skb_tailroom(msdu), 45928c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 45938c2ecf20Sopenharmony_ci rxcb->unmapped = 1; 45948c2ecf20Sopenharmony_ci } 45958c2ecf20Sopenharmony_ci if (drop_mpdu) { 45968c2ecf20Sopenharmony_ci ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 45978c2ecf20Sopenharmony_ci "i %d drop msdu %p *ppdu_id %x\n", 45988c2ecf20Sopenharmony_ci i, msdu, *ppdu_id); 45998c2ecf20Sopenharmony_ci dev_kfree_skb_any(msdu); 46008c2ecf20Sopenharmony_ci msdu = NULL; 46018c2ecf20Sopenharmony_ci goto next_msdu; 46028c2ecf20Sopenharmony_ci } 46038c2ecf20Sopenharmony_ci 46048c2ecf20Sopenharmony_ci rx_desc = (struct hal_rx_desc *)msdu->data; 46058c2ecf20Sopenharmony_ci 46068c2ecf20Sopenharmony_ci rx_pkt_offset = sizeof(struct hal_rx_desc); 46078c2ecf20Sopenharmony_ci l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad(rx_desc); 46088c2ecf20Sopenharmony_ci 46098c2ecf20Sopenharmony_ci if (is_first_msdu) { 46108c2ecf20Sopenharmony_ci if (!ath11k_dp_rxdesc_mpdu_valid(rx_desc)) { 46118c2ecf20Sopenharmony_ci drop_mpdu = true; 46128c2ecf20Sopenharmony_ci dev_kfree_skb_any(msdu); 46138c2ecf20Sopenharmony_ci msdu = NULL; 46148c2ecf20Sopenharmony_ci pmon->mon_last_linkdesc_paddr = paddr; 46158c2ecf20Sopenharmony_ci goto next_msdu; 46168c2ecf20Sopenharmony_ci } 46178c2ecf20Sopenharmony_ci 46188c2ecf20Sopenharmony_ci msdu_ppdu_id = 46198c2ecf20Sopenharmony_ci ath11k_dp_rxdesc_get_ppduid(rx_desc); 46208c2ecf20Sopenharmony_ci 46218c2ecf20Sopenharmony_ci if (ath11k_dp_rx_mon_comp_ppduid(msdu_ppdu_id, 46228c2ecf20Sopenharmony_ci ppdu_id, 46238c2ecf20Sopenharmony_ci &rx_bufs_used)) { 46248c2ecf20Sopenharmony_ci if (rx_bufs_used) { 46258c2ecf20Sopenharmony_ci drop_mpdu = true; 46268c2ecf20Sopenharmony_ci dev_kfree_skb_any(msdu); 46278c2ecf20Sopenharmony_ci msdu = NULL; 46288c2ecf20Sopenharmony_ci goto next_msdu; 46298c2ecf20Sopenharmony_ci } 46308c2ecf20Sopenharmony_ci return rx_bufs_used; 46318c2ecf20Sopenharmony_ci } 46328c2ecf20Sopenharmony_ci pmon->mon_last_linkdesc_paddr = paddr; 46338c2ecf20Sopenharmony_ci is_first_msdu = false; 46348c2ecf20Sopenharmony_ci } 46358c2ecf20Sopenharmony_ci ath11k_dp_mon_get_buf_len(&msdu_list.msdu_info[i], 46368c2ecf20Sopenharmony_ci &is_frag, &total_len, 46378c2ecf20Sopenharmony_ci &frag_len, &msdu_cnt); 46388c2ecf20Sopenharmony_ci rx_buf_size = rx_pkt_offset + l2_hdr_offset + frag_len; 46398c2ecf20Sopenharmony_ci 46408c2ecf20Sopenharmony_ci ath11k_dp_pkt_set_pktlen(msdu, rx_buf_size); 46418c2ecf20Sopenharmony_ci 46428c2ecf20Sopenharmony_ci if (!(*head_msdu)) 46438c2ecf20Sopenharmony_ci *head_msdu = msdu; 46448c2ecf20Sopenharmony_ci else if (last) 46458c2ecf20Sopenharmony_ci last->next = msdu; 46468c2ecf20Sopenharmony_ci 46478c2ecf20Sopenharmony_ci last = msdu; 46488c2ecf20Sopenharmony_cinext_msdu: 46498c2ecf20Sopenharmony_ci pmon->mon_last_buf_cookie = msdu_list.sw_cookie[i]; 46508c2ecf20Sopenharmony_ci rx_bufs_used++; 46518c2ecf20Sopenharmony_ci spin_lock_bh(&rx_ring->idr_lock); 46528c2ecf20Sopenharmony_ci idr_remove(&rx_ring->bufs_idr, buf_id); 46538c2ecf20Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 46548c2ecf20Sopenharmony_ci } 46558c2ecf20Sopenharmony_ci 46568c2ecf20Sopenharmony_ci ath11k_hal_rx_buf_addr_info_set(rx_link_buf_info, paddr, sw_cookie, rbm); 46578c2ecf20Sopenharmony_ci 46588c2ecf20Sopenharmony_ci ath11k_dp_rx_mon_next_link_desc_get(rx_msdu_link_desc, &paddr, 46598c2ecf20Sopenharmony_ci &sw_cookie, &rbm, 46608c2ecf20Sopenharmony_ci &p_buf_addr_info); 46618c2ecf20Sopenharmony_ci 46628c2ecf20Sopenharmony_ci if (ar->ab->hw_params.rxdma1_enable) { 46638c2ecf20Sopenharmony_ci if (ath11k_dp_rx_monitor_link_desc_return(ar, 46648c2ecf20Sopenharmony_ci p_last_buf_addr_info, 46658c2ecf20Sopenharmony_ci dp->mac_id)) 46668c2ecf20Sopenharmony_ci ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 46678c2ecf20Sopenharmony_ci "dp_rx_monitor_link_desc_return failed"); 46688c2ecf20Sopenharmony_ci } else { 46698c2ecf20Sopenharmony_ci ath11k_dp_rx_link_desc_return(ar->ab, rx_link_buf_info, 46708c2ecf20Sopenharmony_ci HAL_WBM_REL_BM_ACT_PUT_IN_IDLE); 46718c2ecf20Sopenharmony_ci } 46728c2ecf20Sopenharmony_ci 46738c2ecf20Sopenharmony_ci p_last_buf_addr_info = p_buf_addr_info; 46748c2ecf20Sopenharmony_ci 46758c2ecf20Sopenharmony_ci } while (paddr && msdu_cnt); 46768c2ecf20Sopenharmony_ci 46778c2ecf20Sopenharmony_ci if (last) 46788c2ecf20Sopenharmony_ci last->next = NULL; 46798c2ecf20Sopenharmony_ci 46808c2ecf20Sopenharmony_ci *tail_msdu = msdu; 46818c2ecf20Sopenharmony_ci 46828c2ecf20Sopenharmony_ci if (msdu_cnt == 0) 46838c2ecf20Sopenharmony_ci *npackets = 1; 46848c2ecf20Sopenharmony_ci 46858c2ecf20Sopenharmony_ci return rx_bufs_used; 46868c2ecf20Sopenharmony_ci} 46878c2ecf20Sopenharmony_ci 46888c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_msdus_set_payload(struct sk_buff *msdu) 46898c2ecf20Sopenharmony_ci{ 46908c2ecf20Sopenharmony_ci u32 rx_pkt_offset, l2_hdr_offset; 46918c2ecf20Sopenharmony_ci 46928c2ecf20Sopenharmony_ci rx_pkt_offset = sizeof(struct hal_rx_desc); 46938c2ecf20Sopenharmony_ci l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad((struct hal_rx_desc *)msdu->data); 46948c2ecf20Sopenharmony_ci skb_pull(msdu, rx_pkt_offset + l2_hdr_offset); 46958c2ecf20Sopenharmony_ci} 46968c2ecf20Sopenharmony_ci 46978c2ecf20Sopenharmony_cistatic struct sk_buff * 46988c2ecf20Sopenharmony_ciath11k_dp_rx_mon_merg_msdus(struct ath11k *ar, 46998c2ecf20Sopenharmony_ci u32 mac_id, struct sk_buff *head_msdu, 47008c2ecf20Sopenharmony_ci struct sk_buff *last_msdu, 47018c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rxs) 47028c2ecf20Sopenharmony_ci{ 47038c2ecf20Sopenharmony_ci struct sk_buff *msdu, *mpdu_buf, *prev_buf; 47048c2ecf20Sopenharmony_ci u32 decap_format, wifi_hdr_len; 47058c2ecf20Sopenharmony_ci struct hal_rx_desc *rx_desc; 47068c2ecf20Sopenharmony_ci char *hdr_desc; 47078c2ecf20Sopenharmony_ci u8 *dest; 47088c2ecf20Sopenharmony_ci struct ieee80211_hdr_3addr *wh; 47098c2ecf20Sopenharmony_ci 47108c2ecf20Sopenharmony_ci mpdu_buf = NULL; 47118c2ecf20Sopenharmony_ci 47128c2ecf20Sopenharmony_ci if (!head_msdu) 47138c2ecf20Sopenharmony_ci goto err_merge_fail; 47148c2ecf20Sopenharmony_ci 47158c2ecf20Sopenharmony_ci rx_desc = (struct hal_rx_desc *)head_msdu->data; 47168c2ecf20Sopenharmony_ci 47178c2ecf20Sopenharmony_ci if (ath11k_dp_rxdesc_get_mpdulen_err(rx_desc)) 47188c2ecf20Sopenharmony_ci return NULL; 47198c2ecf20Sopenharmony_ci 47208c2ecf20Sopenharmony_ci decap_format = ath11k_dp_rxdesc_get_decap_format(rx_desc); 47218c2ecf20Sopenharmony_ci 47228c2ecf20Sopenharmony_ci ath11k_dp_rx_h_ppdu(ar, rx_desc, rxs); 47238c2ecf20Sopenharmony_ci 47248c2ecf20Sopenharmony_ci if (decap_format == DP_RX_DECAP_TYPE_RAW) { 47258c2ecf20Sopenharmony_ci ath11k_dp_rx_msdus_set_payload(head_msdu); 47268c2ecf20Sopenharmony_ci 47278c2ecf20Sopenharmony_ci prev_buf = head_msdu; 47288c2ecf20Sopenharmony_ci msdu = head_msdu->next; 47298c2ecf20Sopenharmony_ci 47308c2ecf20Sopenharmony_ci while (msdu) { 47318c2ecf20Sopenharmony_ci ath11k_dp_rx_msdus_set_payload(msdu); 47328c2ecf20Sopenharmony_ci 47338c2ecf20Sopenharmony_ci prev_buf = msdu; 47348c2ecf20Sopenharmony_ci msdu = msdu->next; 47358c2ecf20Sopenharmony_ci } 47368c2ecf20Sopenharmony_ci 47378c2ecf20Sopenharmony_ci prev_buf->next = NULL; 47388c2ecf20Sopenharmony_ci 47398c2ecf20Sopenharmony_ci skb_trim(prev_buf, prev_buf->len - HAL_RX_FCS_LEN); 47408c2ecf20Sopenharmony_ci } else if (decap_format == DP_RX_DECAP_TYPE_NATIVE_WIFI) { 47418c2ecf20Sopenharmony_ci __le16 qos_field; 47428c2ecf20Sopenharmony_ci u8 qos_pkt = 0; 47438c2ecf20Sopenharmony_ci 47448c2ecf20Sopenharmony_ci rx_desc = (struct hal_rx_desc *)head_msdu->data; 47458c2ecf20Sopenharmony_ci hdr_desc = ath11k_dp_rxdesc_get_80211hdr(rx_desc); 47468c2ecf20Sopenharmony_ci 47478c2ecf20Sopenharmony_ci /* Base size */ 47488c2ecf20Sopenharmony_ci wifi_hdr_len = sizeof(struct ieee80211_hdr_3addr); 47498c2ecf20Sopenharmony_ci wh = (struct ieee80211_hdr_3addr *)hdr_desc; 47508c2ecf20Sopenharmony_ci 47518c2ecf20Sopenharmony_ci if (ieee80211_is_data_qos(wh->frame_control)) { 47528c2ecf20Sopenharmony_ci struct ieee80211_qos_hdr *qwh = 47538c2ecf20Sopenharmony_ci (struct ieee80211_qos_hdr *)hdr_desc; 47548c2ecf20Sopenharmony_ci 47558c2ecf20Sopenharmony_ci qos_field = qwh->qos_ctrl; 47568c2ecf20Sopenharmony_ci qos_pkt = 1; 47578c2ecf20Sopenharmony_ci } 47588c2ecf20Sopenharmony_ci msdu = head_msdu; 47598c2ecf20Sopenharmony_ci 47608c2ecf20Sopenharmony_ci while (msdu) { 47618c2ecf20Sopenharmony_ci rx_desc = (struct hal_rx_desc *)msdu->data; 47628c2ecf20Sopenharmony_ci hdr_desc = ath11k_dp_rxdesc_get_80211hdr(rx_desc); 47638c2ecf20Sopenharmony_ci 47648c2ecf20Sopenharmony_ci if (qos_pkt) { 47658c2ecf20Sopenharmony_ci dest = skb_push(msdu, sizeof(__le16)); 47668c2ecf20Sopenharmony_ci if (!dest) 47678c2ecf20Sopenharmony_ci goto err_merge_fail; 47688c2ecf20Sopenharmony_ci memcpy(dest, hdr_desc, wifi_hdr_len); 47698c2ecf20Sopenharmony_ci memcpy(dest + wifi_hdr_len, 47708c2ecf20Sopenharmony_ci (u8 *)&qos_field, sizeof(__le16)); 47718c2ecf20Sopenharmony_ci } 47728c2ecf20Sopenharmony_ci ath11k_dp_rx_msdus_set_payload(msdu); 47738c2ecf20Sopenharmony_ci prev_buf = msdu; 47748c2ecf20Sopenharmony_ci msdu = msdu->next; 47758c2ecf20Sopenharmony_ci } 47768c2ecf20Sopenharmony_ci dest = skb_put(prev_buf, HAL_RX_FCS_LEN); 47778c2ecf20Sopenharmony_ci if (!dest) 47788c2ecf20Sopenharmony_ci goto err_merge_fail; 47798c2ecf20Sopenharmony_ci 47808c2ecf20Sopenharmony_ci ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 47818c2ecf20Sopenharmony_ci "mpdu_buf %pK mpdu_buf->len %u", 47828c2ecf20Sopenharmony_ci prev_buf, prev_buf->len); 47838c2ecf20Sopenharmony_ci } else { 47848c2ecf20Sopenharmony_ci ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 47858c2ecf20Sopenharmony_ci "decap format %d is not supported!\n", 47868c2ecf20Sopenharmony_ci decap_format); 47878c2ecf20Sopenharmony_ci goto err_merge_fail; 47888c2ecf20Sopenharmony_ci } 47898c2ecf20Sopenharmony_ci 47908c2ecf20Sopenharmony_ci return head_msdu; 47918c2ecf20Sopenharmony_ci 47928c2ecf20Sopenharmony_cierr_merge_fail: 47938c2ecf20Sopenharmony_ci if (mpdu_buf && decap_format != DP_RX_DECAP_TYPE_RAW) { 47948c2ecf20Sopenharmony_ci ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 47958c2ecf20Sopenharmony_ci "err_merge_fail mpdu_buf %pK", mpdu_buf); 47968c2ecf20Sopenharmony_ci /* Free the head buffer */ 47978c2ecf20Sopenharmony_ci dev_kfree_skb_any(mpdu_buf); 47988c2ecf20Sopenharmony_ci } 47998c2ecf20Sopenharmony_ci return NULL; 48008c2ecf20Sopenharmony_ci} 48018c2ecf20Sopenharmony_ci 48028c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_mon_deliver(struct ath11k *ar, u32 mac_id, 48038c2ecf20Sopenharmony_ci struct sk_buff *head_msdu, 48048c2ecf20Sopenharmony_ci struct sk_buff *tail_msdu, 48058c2ecf20Sopenharmony_ci struct napi_struct *napi) 48068c2ecf20Sopenharmony_ci{ 48078c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp = &ar->dp; 48088c2ecf20Sopenharmony_ci struct sk_buff *mon_skb, *skb_next, *header; 48098c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rxs = &dp->rx_status, *status; 48108c2ecf20Sopenharmony_ci 48118c2ecf20Sopenharmony_ci mon_skb = ath11k_dp_rx_mon_merg_msdus(ar, mac_id, head_msdu, 48128c2ecf20Sopenharmony_ci tail_msdu, rxs); 48138c2ecf20Sopenharmony_ci 48148c2ecf20Sopenharmony_ci if (!mon_skb) 48158c2ecf20Sopenharmony_ci goto mon_deliver_fail; 48168c2ecf20Sopenharmony_ci 48178c2ecf20Sopenharmony_ci header = mon_skb; 48188c2ecf20Sopenharmony_ci 48198c2ecf20Sopenharmony_ci rxs->flag = 0; 48208c2ecf20Sopenharmony_ci do { 48218c2ecf20Sopenharmony_ci skb_next = mon_skb->next; 48228c2ecf20Sopenharmony_ci if (!skb_next) 48238c2ecf20Sopenharmony_ci rxs->flag &= ~RX_FLAG_AMSDU_MORE; 48248c2ecf20Sopenharmony_ci else 48258c2ecf20Sopenharmony_ci rxs->flag |= RX_FLAG_AMSDU_MORE; 48268c2ecf20Sopenharmony_ci 48278c2ecf20Sopenharmony_ci if (mon_skb == header) { 48288c2ecf20Sopenharmony_ci header = NULL; 48298c2ecf20Sopenharmony_ci rxs->flag &= ~RX_FLAG_ALLOW_SAME_PN; 48308c2ecf20Sopenharmony_ci } else { 48318c2ecf20Sopenharmony_ci rxs->flag |= RX_FLAG_ALLOW_SAME_PN; 48328c2ecf20Sopenharmony_ci } 48338c2ecf20Sopenharmony_ci rxs->flag |= RX_FLAG_ONLY_MONITOR; 48348c2ecf20Sopenharmony_ci 48358c2ecf20Sopenharmony_ci status = IEEE80211_SKB_RXCB(mon_skb); 48368c2ecf20Sopenharmony_ci *status = *rxs; 48378c2ecf20Sopenharmony_ci 48388c2ecf20Sopenharmony_ci ath11k_dp_rx_deliver_msdu(ar, napi, mon_skb); 48398c2ecf20Sopenharmony_ci mon_skb = skb_next; 48408c2ecf20Sopenharmony_ci } while (mon_skb); 48418c2ecf20Sopenharmony_ci rxs->flag = 0; 48428c2ecf20Sopenharmony_ci 48438c2ecf20Sopenharmony_ci return 0; 48448c2ecf20Sopenharmony_ci 48458c2ecf20Sopenharmony_cimon_deliver_fail: 48468c2ecf20Sopenharmony_ci mon_skb = head_msdu; 48478c2ecf20Sopenharmony_ci while (mon_skb) { 48488c2ecf20Sopenharmony_ci skb_next = mon_skb->next; 48498c2ecf20Sopenharmony_ci dev_kfree_skb_any(mon_skb); 48508c2ecf20Sopenharmony_ci mon_skb = skb_next; 48518c2ecf20Sopenharmony_ci } 48528c2ecf20Sopenharmony_ci return -EINVAL; 48538c2ecf20Sopenharmony_ci} 48548c2ecf20Sopenharmony_ci 48558c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_mon_dest_process(struct ath11k *ar, int mac_id, 48568c2ecf20Sopenharmony_ci u32 quota, struct napi_struct *napi) 48578c2ecf20Sopenharmony_ci{ 48588c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp = &ar->dp; 48598c2ecf20Sopenharmony_ci struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data; 48608c2ecf20Sopenharmony_ci void *ring_entry; 48618c2ecf20Sopenharmony_ci void *mon_dst_srng; 48628c2ecf20Sopenharmony_ci u32 ppdu_id; 48638c2ecf20Sopenharmony_ci u32 rx_bufs_used; 48648c2ecf20Sopenharmony_ci u32 ring_id; 48658c2ecf20Sopenharmony_ci struct ath11k_pdev_mon_stats *rx_mon_stats; 48668c2ecf20Sopenharmony_ci u32 npackets = 0; 48678c2ecf20Sopenharmony_ci 48688c2ecf20Sopenharmony_ci if (ar->ab->hw_params.rxdma1_enable) 48698c2ecf20Sopenharmony_ci ring_id = dp->rxdma_mon_dst_ring.ring_id; 48708c2ecf20Sopenharmony_ci else 48718c2ecf20Sopenharmony_ci ring_id = dp->rxdma_err_dst_ring[mac_id].ring_id; 48728c2ecf20Sopenharmony_ci 48738c2ecf20Sopenharmony_ci mon_dst_srng = &ar->ab->hal.srng_list[ring_id]; 48748c2ecf20Sopenharmony_ci 48758c2ecf20Sopenharmony_ci if (!mon_dst_srng) { 48768c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, 48778c2ecf20Sopenharmony_ci "HAL Monitor Destination Ring Init Failed -- %pK", 48788c2ecf20Sopenharmony_ci mon_dst_srng); 48798c2ecf20Sopenharmony_ci return; 48808c2ecf20Sopenharmony_ci } 48818c2ecf20Sopenharmony_ci 48828c2ecf20Sopenharmony_ci spin_lock_bh(&pmon->mon_lock); 48838c2ecf20Sopenharmony_ci 48848c2ecf20Sopenharmony_ci ath11k_hal_srng_access_begin(ar->ab, mon_dst_srng); 48858c2ecf20Sopenharmony_ci 48868c2ecf20Sopenharmony_ci ppdu_id = pmon->mon_ppdu_info.ppdu_id; 48878c2ecf20Sopenharmony_ci rx_bufs_used = 0; 48888c2ecf20Sopenharmony_ci rx_mon_stats = &pmon->rx_mon_stats; 48898c2ecf20Sopenharmony_ci 48908c2ecf20Sopenharmony_ci while ((ring_entry = ath11k_hal_srng_dst_peek(ar->ab, mon_dst_srng))) { 48918c2ecf20Sopenharmony_ci struct sk_buff *head_msdu, *tail_msdu; 48928c2ecf20Sopenharmony_ci 48938c2ecf20Sopenharmony_ci head_msdu = NULL; 48948c2ecf20Sopenharmony_ci tail_msdu = NULL; 48958c2ecf20Sopenharmony_ci 48968c2ecf20Sopenharmony_ci rx_bufs_used += ath11k_dp_rx_mon_mpdu_pop(ar, mac_id, ring_entry, 48978c2ecf20Sopenharmony_ci &head_msdu, 48988c2ecf20Sopenharmony_ci &tail_msdu, 48998c2ecf20Sopenharmony_ci &npackets, &ppdu_id); 49008c2ecf20Sopenharmony_ci 49018c2ecf20Sopenharmony_ci if (ppdu_id != pmon->mon_ppdu_info.ppdu_id) { 49028c2ecf20Sopenharmony_ci pmon->mon_ppdu_status = DP_PPDU_STATUS_START; 49038c2ecf20Sopenharmony_ci ath11k_dbg(ar->ab, ATH11K_DBG_DATA, 49048c2ecf20Sopenharmony_ci "dest_rx: new ppdu_id %x != status ppdu_id %x", 49058c2ecf20Sopenharmony_ci ppdu_id, pmon->mon_ppdu_info.ppdu_id); 49068c2ecf20Sopenharmony_ci break; 49078c2ecf20Sopenharmony_ci } 49088c2ecf20Sopenharmony_ci if (head_msdu && tail_msdu) { 49098c2ecf20Sopenharmony_ci ath11k_dp_rx_mon_deliver(ar, dp->mac_id, head_msdu, 49108c2ecf20Sopenharmony_ci tail_msdu, napi); 49118c2ecf20Sopenharmony_ci rx_mon_stats->dest_mpdu_done++; 49128c2ecf20Sopenharmony_ci } 49138c2ecf20Sopenharmony_ci 49148c2ecf20Sopenharmony_ci ring_entry = ath11k_hal_srng_dst_get_next_entry(ar->ab, 49158c2ecf20Sopenharmony_ci mon_dst_srng); 49168c2ecf20Sopenharmony_ci } 49178c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ar->ab, mon_dst_srng); 49188c2ecf20Sopenharmony_ci 49198c2ecf20Sopenharmony_ci spin_unlock_bh(&pmon->mon_lock); 49208c2ecf20Sopenharmony_ci 49218c2ecf20Sopenharmony_ci if (rx_bufs_used) { 49228c2ecf20Sopenharmony_ci rx_mon_stats->dest_ppdu_done++; 49238c2ecf20Sopenharmony_ci if (ar->ab->hw_params.rxdma1_enable) 49248c2ecf20Sopenharmony_ci ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, 49258c2ecf20Sopenharmony_ci &dp->rxdma_mon_buf_ring, 49268c2ecf20Sopenharmony_ci rx_bufs_used, 49278c2ecf20Sopenharmony_ci HAL_RX_BUF_RBM_SW3_BM); 49288c2ecf20Sopenharmony_ci else 49298c2ecf20Sopenharmony_ci ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, 49308c2ecf20Sopenharmony_ci &dp->rx_refill_buf_ring, 49318c2ecf20Sopenharmony_ci rx_bufs_used, 49328c2ecf20Sopenharmony_ci HAL_RX_BUF_RBM_SW3_BM); 49338c2ecf20Sopenharmony_ci } 49348c2ecf20Sopenharmony_ci} 49358c2ecf20Sopenharmony_ci 49368c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_mon_status_process_tlv(struct ath11k *ar, 49378c2ecf20Sopenharmony_ci int mac_id, u32 quota, 49388c2ecf20Sopenharmony_ci struct napi_struct *napi) 49398c2ecf20Sopenharmony_ci{ 49408c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp = &ar->dp; 49418c2ecf20Sopenharmony_ci struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data; 49428c2ecf20Sopenharmony_ci struct hal_rx_mon_ppdu_info *ppdu_info; 49438c2ecf20Sopenharmony_ci struct sk_buff *status_skb; 49448c2ecf20Sopenharmony_ci u32 tlv_status = HAL_TLV_STATUS_BUF_DONE; 49458c2ecf20Sopenharmony_ci struct ath11k_pdev_mon_stats *rx_mon_stats; 49468c2ecf20Sopenharmony_ci 49478c2ecf20Sopenharmony_ci ppdu_info = &pmon->mon_ppdu_info; 49488c2ecf20Sopenharmony_ci rx_mon_stats = &pmon->rx_mon_stats; 49498c2ecf20Sopenharmony_ci 49508c2ecf20Sopenharmony_ci if (pmon->mon_ppdu_status != DP_PPDU_STATUS_START) 49518c2ecf20Sopenharmony_ci return; 49528c2ecf20Sopenharmony_ci 49538c2ecf20Sopenharmony_ci while (!skb_queue_empty(&pmon->rx_status_q)) { 49548c2ecf20Sopenharmony_ci status_skb = skb_dequeue(&pmon->rx_status_q); 49558c2ecf20Sopenharmony_ci 49568c2ecf20Sopenharmony_ci tlv_status = ath11k_hal_rx_parse_mon_status(ar->ab, ppdu_info, 49578c2ecf20Sopenharmony_ci status_skb); 49588c2ecf20Sopenharmony_ci if (tlv_status == HAL_TLV_STATUS_PPDU_DONE) { 49598c2ecf20Sopenharmony_ci rx_mon_stats->status_ppdu_done++; 49608c2ecf20Sopenharmony_ci pmon->mon_ppdu_status = DP_PPDU_STATUS_DONE; 49618c2ecf20Sopenharmony_ci ath11k_dp_rx_mon_dest_process(ar, mac_id, quota, napi); 49628c2ecf20Sopenharmony_ci pmon->mon_ppdu_status = DP_PPDU_STATUS_START; 49638c2ecf20Sopenharmony_ci } 49648c2ecf20Sopenharmony_ci dev_kfree_skb_any(status_skb); 49658c2ecf20Sopenharmony_ci } 49668c2ecf20Sopenharmony_ci} 49678c2ecf20Sopenharmony_ci 49688c2ecf20Sopenharmony_cistatic int ath11k_dp_mon_process_rx(struct ath11k_base *ab, int mac_id, 49698c2ecf20Sopenharmony_ci struct napi_struct *napi, int budget) 49708c2ecf20Sopenharmony_ci{ 49718c2ecf20Sopenharmony_ci struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); 49728c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp = &ar->dp; 49738c2ecf20Sopenharmony_ci struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data; 49748c2ecf20Sopenharmony_ci int num_buffs_reaped = 0; 49758c2ecf20Sopenharmony_ci 49768c2ecf20Sopenharmony_ci num_buffs_reaped = ath11k_dp_rx_reap_mon_status_ring(ar->ab, mac_id, &budget, 49778c2ecf20Sopenharmony_ci &pmon->rx_status_q); 49788c2ecf20Sopenharmony_ci if (num_buffs_reaped) 49798c2ecf20Sopenharmony_ci ath11k_dp_rx_mon_status_process_tlv(ar, mac_id, budget, napi); 49808c2ecf20Sopenharmony_ci 49818c2ecf20Sopenharmony_ci return num_buffs_reaped; 49828c2ecf20Sopenharmony_ci} 49838c2ecf20Sopenharmony_ci 49848c2ecf20Sopenharmony_ciint ath11k_dp_rx_process_mon_rings(struct ath11k_base *ab, int mac_id, 49858c2ecf20Sopenharmony_ci struct napi_struct *napi, int budget) 49868c2ecf20Sopenharmony_ci{ 49878c2ecf20Sopenharmony_ci struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); 49888c2ecf20Sopenharmony_ci int ret = 0; 49898c2ecf20Sopenharmony_ci 49908c2ecf20Sopenharmony_ci if (test_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags)) 49918c2ecf20Sopenharmony_ci ret = ath11k_dp_mon_process_rx(ab, mac_id, napi, budget); 49928c2ecf20Sopenharmony_ci else 49938c2ecf20Sopenharmony_ci ret = ath11k_dp_rx_process_mon_status(ab, mac_id, napi, budget); 49948c2ecf20Sopenharmony_ci return ret; 49958c2ecf20Sopenharmony_ci} 49968c2ecf20Sopenharmony_ci 49978c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_pdev_mon_status_attach(struct ath11k *ar) 49988c2ecf20Sopenharmony_ci{ 49998c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp = &ar->dp; 50008c2ecf20Sopenharmony_ci struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data; 50018c2ecf20Sopenharmony_ci 50028c2ecf20Sopenharmony_ci skb_queue_head_init(&pmon->rx_status_q); 50038c2ecf20Sopenharmony_ci 50048c2ecf20Sopenharmony_ci pmon->mon_ppdu_status = DP_PPDU_STATUS_START; 50058c2ecf20Sopenharmony_ci 50068c2ecf20Sopenharmony_ci memset(&pmon->rx_mon_stats, 0, 50078c2ecf20Sopenharmony_ci sizeof(pmon->rx_mon_stats)); 50088c2ecf20Sopenharmony_ci return 0; 50098c2ecf20Sopenharmony_ci} 50108c2ecf20Sopenharmony_ci 50118c2ecf20Sopenharmony_ciint ath11k_dp_rx_pdev_mon_attach(struct ath11k *ar) 50128c2ecf20Sopenharmony_ci{ 50138c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp = &ar->dp; 50148c2ecf20Sopenharmony_ci struct ath11k_mon_data *pmon = &dp->mon_data; 50158c2ecf20Sopenharmony_ci struct hal_srng *mon_desc_srng = NULL; 50168c2ecf20Sopenharmony_ci struct dp_srng *dp_srng; 50178c2ecf20Sopenharmony_ci int ret = 0; 50188c2ecf20Sopenharmony_ci u32 n_link_desc = 0; 50198c2ecf20Sopenharmony_ci 50208c2ecf20Sopenharmony_ci ret = ath11k_dp_rx_pdev_mon_status_attach(ar); 50218c2ecf20Sopenharmony_ci if (ret) { 50228c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "pdev_mon_status_attach() failed"); 50238c2ecf20Sopenharmony_ci return ret; 50248c2ecf20Sopenharmony_ci } 50258c2ecf20Sopenharmony_ci 50268c2ecf20Sopenharmony_ci /* if rxdma1_enable is false, no need to setup 50278c2ecf20Sopenharmony_ci * rxdma_mon_desc_ring. 50288c2ecf20Sopenharmony_ci */ 50298c2ecf20Sopenharmony_ci if (!ar->ab->hw_params.rxdma1_enable) 50308c2ecf20Sopenharmony_ci return 0; 50318c2ecf20Sopenharmony_ci 50328c2ecf20Sopenharmony_ci dp_srng = &dp->rxdma_mon_desc_ring; 50338c2ecf20Sopenharmony_ci n_link_desc = dp_srng->size / 50348c2ecf20Sopenharmony_ci ath11k_hal_srng_get_entrysize(ar->ab, HAL_RXDMA_MONITOR_DESC); 50358c2ecf20Sopenharmony_ci mon_desc_srng = 50368c2ecf20Sopenharmony_ci &ar->ab->hal.srng_list[dp->rxdma_mon_desc_ring.ring_id]; 50378c2ecf20Sopenharmony_ci 50388c2ecf20Sopenharmony_ci ret = ath11k_dp_link_desc_setup(ar->ab, pmon->link_desc_banks, 50398c2ecf20Sopenharmony_ci HAL_RXDMA_MONITOR_DESC, mon_desc_srng, 50408c2ecf20Sopenharmony_ci n_link_desc); 50418c2ecf20Sopenharmony_ci if (ret) { 50428c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "mon_link_desc_pool_setup() failed"); 50438c2ecf20Sopenharmony_ci return ret; 50448c2ecf20Sopenharmony_ci } 50458c2ecf20Sopenharmony_ci pmon->mon_last_linkdesc_paddr = 0; 50468c2ecf20Sopenharmony_ci pmon->mon_last_buf_cookie = DP_RX_DESC_COOKIE_MAX + 1; 50478c2ecf20Sopenharmony_ci spin_lock_init(&pmon->mon_lock); 50488c2ecf20Sopenharmony_ci 50498c2ecf20Sopenharmony_ci return 0; 50508c2ecf20Sopenharmony_ci} 50518c2ecf20Sopenharmony_ci 50528c2ecf20Sopenharmony_cistatic int ath11k_dp_mon_link_free(struct ath11k *ar) 50538c2ecf20Sopenharmony_ci{ 50548c2ecf20Sopenharmony_ci struct ath11k_pdev_dp *dp = &ar->dp; 50558c2ecf20Sopenharmony_ci struct ath11k_mon_data *pmon = &dp->mon_data; 50568c2ecf20Sopenharmony_ci 50578c2ecf20Sopenharmony_ci ath11k_dp_link_desc_cleanup(ar->ab, pmon->link_desc_banks, 50588c2ecf20Sopenharmony_ci HAL_RXDMA_MONITOR_DESC, 50598c2ecf20Sopenharmony_ci &dp->rxdma_mon_desc_ring); 50608c2ecf20Sopenharmony_ci return 0; 50618c2ecf20Sopenharmony_ci} 50628c2ecf20Sopenharmony_ci 50638c2ecf20Sopenharmony_ciint ath11k_dp_rx_pdev_mon_detach(struct ath11k *ar) 50648c2ecf20Sopenharmony_ci{ 50658c2ecf20Sopenharmony_ci ath11k_dp_mon_link_free(ar); 50668c2ecf20Sopenharmony_ci return 0; 50678c2ecf20Sopenharmony_ci} 5068