162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause-Clear 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/ieee80211.h> 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/skbuff.h> 1062306a36Sopenharmony_ci#include <crypto/hash.h> 1162306a36Sopenharmony_ci#include "core.h" 1262306a36Sopenharmony_ci#include "debug.h" 1362306a36Sopenharmony_ci#include "hal_desc.h" 1462306a36Sopenharmony_ci#include "hw.h" 1562306a36Sopenharmony_ci#include "dp_rx.h" 1662306a36Sopenharmony_ci#include "hal_rx.h" 1762306a36Sopenharmony_ci#include "dp_tx.h" 1862306a36Sopenharmony_ci#include "peer.h" 1962306a36Sopenharmony_ci#include "dp_mon.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define ATH12K_DP_RX_FRAGMENT_TIMEOUT_MS (2 * HZ) 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic enum hal_encrypt_type ath12k_dp_rx_h_enctype(struct ath12k_base *ab, 2462306a36Sopenharmony_ci struct hal_rx_desc *desc) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci if (!ab->hw_params->hal_ops->rx_desc_encrypt_valid(desc)) 2762306a36Sopenharmony_ci return HAL_ENCRYPT_TYPE_OPEN; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_get_encrypt_type(desc); 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ciu8 ath12k_dp_rx_h_decap_type(struct ath12k_base *ab, 3362306a36Sopenharmony_ci struct hal_rx_desc *desc) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_get_decap_type(desc); 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic u8 ath12k_dp_rx_h_mesh_ctl_present(struct ath12k_base *ab, 3962306a36Sopenharmony_ci struct hal_rx_desc *desc) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_get_mesh_ctl(desc); 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic bool ath12k_dp_rx_h_seq_ctrl_valid(struct ath12k_base *ab, 4562306a36Sopenharmony_ci struct hal_rx_desc *desc) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_get_mpdu_seq_ctl_vld(desc); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic bool ath12k_dp_rx_h_fc_valid(struct ath12k_base *ab, 5162306a36Sopenharmony_ci struct hal_rx_desc *desc) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_get_mpdu_fc_valid(desc); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic bool ath12k_dp_rx_h_more_frags(struct ath12k_base *ab, 5762306a36Sopenharmony_ci struct sk_buff *skb) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)(skb->data + ab->hw_params->hal_desc_sz); 6262306a36Sopenharmony_ci return ieee80211_has_morefrags(hdr->frame_control); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic u16 ath12k_dp_rx_h_frag_no(struct ath12k_base *ab, 6662306a36Sopenharmony_ci struct sk_buff *skb) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)(skb->data + ab->hw_params->hal_desc_sz); 7162306a36Sopenharmony_ci return le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic u16 ath12k_dp_rx_h_seq_no(struct ath12k_base *ab, 7562306a36Sopenharmony_ci struct hal_rx_desc *desc) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_get_mpdu_start_seq_no(desc); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic bool ath12k_dp_rx_h_msdu_done(struct ath12k_base *ab, 8162306a36Sopenharmony_ci struct hal_rx_desc *desc) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci return ab->hw_params->hal_ops->dp_rx_h_msdu_done(desc); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic bool ath12k_dp_rx_h_l4_cksum_fail(struct ath12k_base *ab, 8762306a36Sopenharmony_ci struct hal_rx_desc *desc) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci return ab->hw_params->hal_ops->dp_rx_h_l4_cksum_fail(desc); 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic bool ath12k_dp_rx_h_ip_cksum_fail(struct ath12k_base *ab, 9362306a36Sopenharmony_ci struct hal_rx_desc *desc) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci return ab->hw_params->hal_ops->dp_rx_h_ip_cksum_fail(desc); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic bool ath12k_dp_rx_h_is_decrypted(struct ath12k_base *ab, 9962306a36Sopenharmony_ci struct hal_rx_desc *desc) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci return ab->hw_params->hal_ops->dp_rx_h_is_decrypted(desc); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ciu32 ath12k_dp_rx_h_mpdu_err(struct ath12k_base *ab, 10562306a36Sopenharmony_ci struct hal_rx_desc *desc) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci return ab->hw_params->hal_ops->dp_rx_h_mpdu_err(desc); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic u16 ath12k_dp_rx_h_msdu_len(struct ath12k_base *ab, 11162306a36Sopenharmony_ci struct hal_rx_desc *desc) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_get_msdu_len(desc); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic u8 ath12k_dp_rx_h_sgi(struct ath12k_base *ab, 11762306a36Sopenharmony_ci struct hal_rx_desc *desc) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_get_msdu_sgi(desc); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic u8 ath12k_dp_rx_h_rate_mcs(struct ath12k_base *ab, 12362306a36Sopenharmony_ci struct hal_rx_desc *desc) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_get_msdu_rate_mcs(desc); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic u8 ath12k_dp_rx_h_rx_bw(struct ath12k_base *ab, 12962306a36Sopenharmony_ci struct hal_rx_desc *desc) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_get_msdu_rx_bw(desc); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic u32 ath12k_dp_rx_h_freq(struct ath12k_base *ab, 13562306a36Sopenharmony_ci struct hal_rx_desc *desc) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_get_msdu_freq(desc); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic u8 ath12k_dp_rx_h_pkt_type(struct ath12k_base *ab, 14162306a36Sopenharmony_ci struct hal_rx_desc *desc) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_get_msdu_pkt_type(desc); 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic u8 ath12k_dp_rx_h_nss(struct ath12k_base *ab, 14762306a36Sopenharmony_ci struct hal_rx_desc *desc) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci return hweight8(ab->hw_params->hal_ops->rx_desc_get_msdu_nss(desc)); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic u8 ath12k_dp_rx_h_tid(struct ath12k_base *ab, 15362306a36Sopenharmony_ci struct hal_rx_desc *desc) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_get_mpdu_tid(desc); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic u16 ath12k_dp_rx_h_peer_id(struct ath12k_base *ab, 15962306a36Sopenharmony_ci struct hal_rx_desc *desc) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_get_mpdu_peer_id(desc); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ciu8 ath12k_dp_rx_h_l3pad(struct ath12k_base *ab, 16562306a36Sopenharmony_ci struct hal_rx_desc *desc) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_get_l3_pad_bytes(desc); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic bool ath12k_dp_rx_h_first_msdu(struct ath12k_base *ab, 17162306a36Sopenharmony_ci struct hal_rx_desc *desc) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_get_first_msdu(desc); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic bool ath12k_dp_rx_h_last_msdu(struct ath12k_base *ab, 17762306a36Sopenharmony_ci struct hal_rx_desc *desc) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_get_last_msdu(desc); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic void ath12k_dp_rx_desc_end_tlv_copy(struct ath12k_base *ab, 18362306a36Sopenharmony_ci struct hal_rx_desc *fdesc, 18462306a36Sopenharmony_ci struct hal_rx_desc *ldesc) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci ab->hw_params->hal_ops->rx_desc_copy_end_tlv(fdesc, ldesc); 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic void ath12k_dp_rxdesc_set_msdu_len(struct ath12k_base *ab, 19062306a36Sopenharmony_ci struct hal_rx_desc *desc, 19162306a36Sopenharmony_ci u16 len) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci ab->hw_params->hal_ops->rx_desc_set_msdu_len(desc, len); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic bool ath12k_dp_rx_h_is_da_mcbc(struct ath12k_base *ab, 19762306a36Sopenharmony_ci struct hal_rx_desc *desc) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci return (ath12k_dp_rx_h_first_msdu(ab, desc) && 20062306a36Sopenharmony_ci ab->hw_params->hal_ops->rx_desc_is_da_mcbc(desc)); 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic bool ath12k_dp_rxdesc_mac_addr2_valid(struct ath12k_base *ab, 20462306a36Sopenharmony_ci struct hal_rx_desc *desc) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_mac_addr2_valid(desc); 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic u8 *ath12k_dp_rxdesc_get_mpdu_start_addr2(struct ath12k_base *ab, 21062306a36Sopenharmony_ci struct hal_rx_desc *desc) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_mpdu_start_addr2(desc); 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic void ath12k_dp_rx_desc_get_dot11_hdr(struct ath12k_base *ab, 21662306a36Sopenharmony_ci struct hal_rx_desc *desc, 21762306a36Sopenharmony_ci struct ieee80211_hdr *hdr) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci ab->hw_params->hal_ops->rx_desc_get_dot11_hdr(desc, hdr); 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic void ath12k_dp_rx_desc_get_crypto_header(struct ath12k_base *ab, 22362306a36Sopenharmony_ci struct hal_rx_desc *desc, 22462306a36Sopenharmony_ci u8 *crypto_hdr, 22562306a36Sopenharmony_ci enum hal_encrypt_type enctype) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci ab->hw_params->hal_ops->rx_desc_get_crypto_header(desc, crypto_hdr, enctype); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic u16 ath12k_dp_rxdesc_get_mpdu_frame_ctrl(struct ath12k_base *ab, 23162306a36Sopenharmony_ci struct hal_rx_desc *desc) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci return ab->hw_params->hal_ops->rx_desc_get_mpdu_frame_ctl(desc); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic int ath12k_dp_purge_mon_ring(struct ath12k_base *ab) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci int i, reaped = 0; 23962306a36Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(DP_MON_PURGE_TIMEOUT_MS); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci do { 24262306a36Sopenharmony_ci for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) 24362306a36Sopenharmony_ci reaped += ath12k_dp_mon_process_ring(ab, i, NULL, 24462306a36Sopenharmony_ci DP_MON_SERVICE_BUDGET, 24562306a36Sopenharmony_ci ATH12K_DP_RX_MONITOR_MODE); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* nothing more to reap */ 24862306a36Sopenharmony_ci if (reaped < DP_MON_SERVICE_BUDGET) 24962306a36Sopenharmony_ci return 0; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci } while (time_before(jiffies, timeout)); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci ath12k_warn(ab, "dp mon ring purge timeout"); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci return -ETIMEDOUT; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/* Returns number of Rx buffers replenished */ 25962306a36Sopenharmony_ciint ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, int mac_id, 26062306a36Sopenharmony_ci struct dp_rxdma_ring *rx_ring, 26162306a36Sopenharmony_ci int req_entries, 26262306a36Sopenharmony_ci enum hal_rx_buf_return_buf_manager mgr, 26362306a36Sopenharmony_ci bool hw_cc) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct ath12k_buffer_addr *desc; 26662306a36Sopenharmony_ci struct hal_srng *srng; 26762306a36Sopenharmony_ci struct sk_buff *skb; 26862306a36Sopenharmony_ci int num_free; 26962306a36Sopenharmony_ci int num_remain; 27062306a36Sopenharmony_ci int buf_id; 27162306a36Sopenharmony_ci u32 cookie; 27262306a36Sopenharmony_ci dma_addr_t paddr; 27362306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 27462306a36Sopenharmony_ci struct ath12k_rx_desc_info *rx_desc; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci req_entries = min(req_entries, rx_ring->bufs_max); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci srng = &ab->hal.srng_list[rx_ring->refill_buf_ring.ring_id]; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci spin_lock_bh(&srng->lock); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci ath12k_hal_srng_access_begin(ab, srng); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci num_free = ath12k_hal_srng_src_num_free(ab, srng, true); 28562306a36Sopenharmony_ci if (!req_entries && (num_free > (rx_ring->bufs_max * 3) / 4)) 28662306a36Sopenharmony_ci req_entries = num_free; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci req_entries = min(num_free, req_entries); 28962306a36Sopenharmony_ci num_remain = req_entries; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci while (num_remain > 0) { 29262306a36Sopenharmony_ci skb = dev_alloc_skb(DP_RX_BUFFER_SIZE + 29362306a36Sopenharmony_ci DP_RX_BUFFER_ALIGN_SIZE); 29462306a36Sopenharmony_ci if (!skb) 29562306a36Sopenharmony_ci break; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (!IS_ALIGNED((unsigned long)skb->data, 29862306a36Sopenharmony_ci DP_RX_BUFFER_ALIGN_SIZE)) { 29962306a36Sopenharmony_ci skb_pull(skb, 30062306a36Sopenharmony_ci PTR_ALIGN(skb->data, DP_RX_BUFFER_ALIGN_SIZE) - 30162306a36Sopenharmony_ci skb->data); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci paddr = dma_map_single(ab->dev, skb->data, 30562306a36Sopenharmony_ci skb->len + skb_tailroom(skb), 30662306a36Sopenharmony_ci DMA_FROM_DEVICE); 30762306a36Sopenharmony_ci if (dma_mapping_error(ab->dev, paddr)) 30862306a36Sopenharmony_ci goto fail_free_skb; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (hw_cc) { 31162306a36Sopenharmony_ci spin_lock_bh(&dp->rx_desc_lock); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* Get desc from free list and store in used list 31462306a36Sopenharmony_ci * for cleanup purposes 31562306a36Sopenharmony_ci * 31662306a36Sopenharmony_ci * TODO: pass the removed descs rather than 31762306a36Sopenharmony_ci * add/read to optimize 31862306a36Sopenharmony_ci */ 31962306a36Sopenharmony_ci rx_desc = list_first_entry_or_null(&dp->rx_desc_free_list, 32062306a36Sopenharmony_ci struct ath12k_rx_desc_info, 32162306a36Sopenharmony_ci list); 32262306a36Sopenharmony_ci if (!rx_desc) { 32362306a36Sopenharmony_ci spin_unlock_bh(&dp->rx_desc_lock); 32462306a36Sopenharmony_ci goto fail_dma_unmap; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci rx_desc->skb = skb; 32862306a36Sopenharmony_ci cookie = rx_desc->cookie; 32962306a36Sopenharmony_ci list_del(&rx_desc->list); 33062306a36Sopenharmony_ci list_add_tail(&rx_desc->list, &dp->rx_desc_used_list); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci spin_unlock_bh(&dp->rx_desc_lock); 33362306a36Sopenharmony_ci } else { 33462306a36Sopenharmony_ci spin_lock_bh(&rx_ring->idr_lock); 33562306a36Sopenharmony_ci buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 0, 33662306a36Sopenharmony_ci rx_ring->bufs_max * 3, GFP_ATOMIC); 33762306a36Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 33862306a36Sopenharmony_ci if (buf_id < 0) 33962306a36Sopenharmony_ci goto fail_dma_unmap; 34062306a36Sopenharmony_ci cookie = u32_encode_bits(mac_id, 34162306a36Sopenharmony_ci DP_RXDMA_BUF_COOKIE_PDEV_ID) | 34262306a36Sopenharmony_ci u32_encode_bits(buf_id, 34362306a36Sopenharmony_ci DP_RXDMA_BUF_COOKIE_BUF_ID); 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci desc = ath12k_hal_srng_src_get_next_entry(ab, srng); 34762306a36Sopenharmony_ci if (!desc) 34862306a36Sopenharmony_ci goto fail_buf_unassign; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci ATH12K_SKB_RXCB(skb)->paddr = paddr; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci num_remain--; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci ath12k_hal_rx_buf_addr_info_set(desc, paddr, cookie, mgr); 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci ath12k_hal_srng_access_end(ab, srng); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci spin_unlock_bh(&srng->lock); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci return req_entries - num_remain; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cifail_buf_unassign: 36462306a36Sopenharmony_ci if (hw_cc) { 36562306a36Sopenharmony_ci spin_lock_bh(&dp->rx_desc_lock); 36662306a36Sopenharmony_ci list_del(&rx_desc->list); 36762306a36Sopenharmony_ci list_add_tail(&rx_desc->list, &dp->rx_desc_free_list); 36862306a36Sopenharmony_ci rx_desc->skb = NULL; 36962306a36Sopenharmony_ci spin_unlock_bh(&dp->rx_desc_lock); 37062306a36Sopenharmony_ci } else { 37162306a36Sopenharmony_ci spin_lock_bh(&rx_ring->idr_lock); 37262306a36Sopenharmony_ci idr_remove(&rx_ring->bufs_idr, buf_id); 37362306a36Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_cifail_dma_unmap: 37662306a36Sopenharmony_ci dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb), 37762306a36Sopenharmony_ci DMA_FROM_DEVICE); 37862306a36Sopenharmony_cifail_free_skb: 37962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci ath12k_hal_srng_access_end(ab, srng); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci spin_unlock_bh(&srng->lock); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci return req_entries - num_remain; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic int ath12k_dp_rxdma_buf_ring_free(struct ath12k_base *ab, 38962306a36Sopenharmony_ci struct dp_rxdma_ring *rx_ring) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci struct sk_buff *skb; 39262306a36Sopenharmony_ci int buf_id; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci spin_lock_bh(&rx_ring->idr_lock); 39562306a36Sopenharmony_ci idr_for_each_entry(&rx_ring->bufs_idr, skb, buf_id) { 39662306a36Sopenharmony_ci idr_remove(&rx_ring->bufs_idr, buf_id); 39762306a36Sopenharmony_ci /* TODO: Understand where internal driver does this dma_unmap 39862306a36Sopenharmony_ci * of rxdma_buffer. 39962306a36Sopenharmony_ci */ 40062306a36Sopenharmony_ci dma_unmap_single(ab->dev, ATH12K_SKB_RXCB(skb)->paddr, 40162306a36Sopenharmony_ci skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); 40262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci idr_destroy(&rx_ring->bufs_idr); 40662306a36Sopenharmony_ci spin_unlock_bh(&rx_ring->idr_lock); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci return 0; 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic int ath12k_dp_rxdma_buf_free(struct ath12k_base *ab) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 41462306a36Sopenharmony_ci struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci ath12k_dp_rxdma_buf_ring_free(ab, rx_ring); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci rx_ring = &dp->rxdma_mon_buf_ring; 41962306a36Sopenharmony_ci ath12k_dp_rxdma_buf_ring_free(ab, rx_ring); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci rx_ring = &dp->tx_mon_buf_ring; 42262306a36Sopenharmony_ci ath12k_dp_rxdma_buf_ring_free(ab, rx_ring); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci return 0; 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic int ath12k_dp_rxdma_ring_buf_setup(struct ath12k_base *ab, 42862306a36Sopenharmony_ci struct dp_rxdma_ring *rx_ring, 42962306a36Sopenharmony_ci u32 ringtype) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci int num_entries; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci num_entries = rx_ring->refill_buf_ring.size / 43462306a36Sopenharmony_ci ath12k_hal_srng_get_entrysize(ab, ringtype); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci rx_ring->bufs_max = num_entries; 43762306a36Sopenharmony_ci if ((ringtype == HAL_RXDMA_MONITOR_BUF) || (ringtype == HAL_TX_MONITOR_BUF)) 43862306a36Sopenharmony_ci ath12k_dp_mon_buf_replenish(ab, rx_ring, num_entries); 43962306a36Sopenharmony_ci else 44062306a36Sopenharmony_ci ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, num_entries, 44162306a36Sopenharmony_ci ab->hw_params->hal_params->rx_buf_rbm, 44262306a36Sopenharmony_ci ringtype == HAL_RXDMA_BUF); 44362306a36Sopenharmony_ci return 0; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic int ath12k_dp_rxdma_buf_setup(struct ath12k_base *ab) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 44962306a36Sopenharmony_ci struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; 45062306a36Sopenharmony_ci int ret; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci ret = ath12k_dp_rxdma_ring_buf_setup(ab, rx_ring, 45362306a36Sopenharmony_ci HAL_RXDMA_BUF); 45462306a36Sopenharmony_ci if (ret) { 45562306a36Sopenharmony_ci ath12k_warn(ab, 45662306a36Sopenharmony_ci "failed to setup HAL_RXDMA_BUF\n"); 45762306a36Sopenharmony_ci return ret; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (ab->hw_params->rxdma1_enable) { 46162306a36Sopenharmony_ci rx_ring = &dp->rxdma_mon_buf_ring; 46262306a36Sopenharmony_ci ret = ath12k_dp_rxdma_ring_buf_setup(ab, rx_ring, 46362306a36Sopenharmony_ci HAL_RXDMA_MONITOR_BUF); 46462306a36Sopenharmony_ci if (ret) { 46562306a36Sopenharmony_ci ath12k_warn(ab, 46662306a36Sopenharmony_ci "failed to setup HAL_RXDMA_MONITOR_BUF\n"); 46762306a36Sopenharmony_ci return ret; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci rx_ring = &dp->tx_mon_buf_ring; 47162306a36Sopenharmony_ci ret = ath12k_dp_rxdma_ring_buf_setup(ab, rx_ring, 47262306a36Sopenharmony_ci HAL_TX_MONITOR_BUF); 47362306a36Sopenharmony_ci if (ret) { 47462306a36Sopenharmony_ci ath12k_warn(ab, 47562306a36Sopenharmony_ci "failed to setup HAL_TX_MONITOR_BUF\n"); 47662306a36Sopenharmony_ci return ret; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci return 0; 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic void ath12k_dp_rx_pdev_srng_free(struct ath12k *ar) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct ath12k_pdev_dp *dp = &ar->dp; 48662306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 48762306a36Sopenharmony_ci int i; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) { 49062306a36Sopenharmony_ci ath12k_dp_srng_cleanup(ab, &dp->rxdma_mon_dst_ring[i]); 49162306a36Sopenharmony_ci ath12k_dp_srng_cleanup(ab, &dp->tx_mon_dst_ring[i]); 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_civoid ath12k_dp_rx_pdev_reo_cleanup(struct ath12k_base *ab) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 49862306a36Sopenharmony_ci int i; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci for (i = 0; i < DP_REO_DST_RING_MAX; i++) 50162306a36Sopenharmony_ci ath12k_dp_srng_cleanup(ab, &dp->reo_dst_ring[i]); 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ciint ath12k_dp_rx_pdev_reo_setup(struct ath12k_base *ab) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 50762306a36Sopenharmony_ci int ret; 50862306a36Sopenharmony_ci int i; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci for (i = 0; i < DP_REO_DST_RING_MAX; i++) { 51162306a36Sopenharmony_ci ret = ath12k_dp_srng_setup(ab, &dp->reo_dst_ring[i], 51262306a36Sopenharmony_ci HAL_REO_DST, i, 0, 51362306a36Sopenharmony_ci DP_REO_DST_RING_SIZE); 51462306a36Sopenharmony_ci if (ret) { 51562306a36Sopenharmony_ci ath12k_warn(ab, "failed to setup reo_dst_ring\n"); 51662306a36Sopenharmony_ci goto err_reo_cleanup; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return 0; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cierr_reo_cleanup: 52362306a36Sopenharmony_ci ath12k_dp_rx_pdev_reo_cleanup(ab); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci return ret; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic int ath12k_dp_rx_pdev_srng_alloc(struct ath12k *ar) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci struct ath12k_pdev_dp *dp = &ar->dp; 53162306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 53262306a36Sopenharmony_ci int i; 53362306a36Sopenharmony_ci int ret; 53462306a36Sopenharmony_ci u32 mac_id = dp->mac_id; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) { 53762306a36Sopenharmony_ci ret = ath12k_dp_srng_setup(ar->ab, 53862306a36Sopenharmony_ci &dp->rxdma_mon_dst_ring[i], 53962306a36Sopenharmony_ci HAL_RXDMA_MONITOR_DST, 54062306a36Sopenharmony_ci 0, mac_id + i, 54162306a36Sopenharmony_ci DP_RXDMA_MONITOR_DST_RING_SIZE); 54262306a36Sopenharmony_ci if (ret) { 54362306a36Sopenharmony_ci ath12k_warn(ar->ab, 54462306a36Sopenharmony_ci "failed to setup HAL_RXDMA_MONITOR_DST\n"); 54562306a36Sopenharmony_ci return ret; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci ret = ath12k_dp_srng_setup(ar->ab, 54962306a36Sopenharmony_ci &dp->tx_mon_dst_ring[i], 55062306a36Sopenharmony_ci HAL_TX_MONITOR_DST, 55162306a36Sopenharmony_ci 0, mac_id + i, 55262306a36Sopenharmony_ci DP_TX_MONITOR_DEST_RING_SIZE); 55362306a36Sopenharmony_ci if (ret) { 55462306a36Sopenharmony_ci ath12k_warn(ar->ab, 55562306a36Sopenharmony_ci "failed to setup HAL_TX_MONITOR_DST\n"); 55662306a36Sopenharmony_ci return ret; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci return 0; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_civoid ath12k_dp_rx_reo_cmd_list_cleanup(struct ath12k_base *ab) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 56662306a36Sopenharmony_ci struct ath12k_dp_rx_reo_cmd *cmd, *tmp; 56762306a36Sopenharmony_ci struct ath12k_dp_rx_reo_cache_flush_elem *cmd_cache, *tmp_cache; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci spin_lock_bh(&dp->reo_cmd_lock); 57062306a36Sopenharmony_ci list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) { 57162306a36Sopenharmony_ci list_del(&cmd->list); 57262306a36Sopenharmony_ci dma_unmap_single(ab->dev, cmd->data.paddr, 57362306a36Sopenharmony_ci cmd->data.size, DMA_BIDIRECTIONAL); 57462306a36Sopenharmony_ci kfree(cmd->data.vaddr); 57562306a36Sopenharmony_ci kfree(cmd); 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci list_for_each_entry_safe(cmd_cache, tmp_cache, 57962306a36Sopenharmony_ci &dp->reo_cmd_cache_flush_list, list) { 58062306a36Sopenharmony_ci list_del(&cmd_cache->list); 58162306a36Sopenharmony_ci dp->reo_cmd_cache_flush_count--; 58262306a36Sopenharmony_ci dma_unmap_single(ab->dev, cmd_cache->data.paddr, 58362306a36Sopenharmony_ci cmd_cache->data.size, DMA_BIDIRECTIONAL); 58462306a36Sopenharmony_ci kfree(cmd_cache->data.vaddr); 58562306a36Sopenharmony_ci kfree(cmd_cache); 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci spin_unlock_bh(&dp->reo_cmd_lock); 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic void ath12k_dp_reo_cmd_free(struct ath12k_dp *dp, void *ctx, 59162306a36Sopenharmony_ci enum hal_reo_cmd_status status) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci struct ath12k_dp_rx_tid *rx_tid = ctx; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (status != HAL_REO_CMD_SUCCESS) 59662306a36Sopenharmony_ci ath12k_warn(dp->ab, "failed to flush rx tid hw desc, tid %d status %d\n", 59762306a36Sopenharmony_ci rx_tid->tid, status); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size, 60062306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 60162306a36Sopenharmony_ci kfree(rx_tid->vaddr); 60262306a36Sopenharmony_ci rx_tid->vaddr = NULL; 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic int ath12k_dp_reo_cmd_send(struct ath12k_base *ab, struct ath12k_dp_rx_tid *rx_tid, 60662306a36Sopenharmony_ci enum hal_reo_cmd_type type, 60762306a36Sopenharmony_ci struct ath12k_hal_reo_cmd *cmd, 60862306a36Sopenharmony_ci void (*cb)(struct ath12k_dp *dp, void *ctx, 60962306a36Sopenharmony_ci enum hal_reo_cmd_status status)) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 61262306a36Sopenharmony_ci struct ath12k_dp_rx_reo_cmd *dp_cmd; 61362306a36Sopenharmony_ci struct hal_srng *cmd_ring; 61462306a36Sopenharmony_ci int cmd_num; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci cmd_ring = &ab->hal.srng_list[dp->reo_cmd_ring.ring_id]; 61762306a36Sopenharmony_ci cmd_num = ath12k_hal_reo_cmd_send(ab, cmd_ring, type, cmd); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci /* cmd_num should start from 1, during failure return the error code */ 62062306a36Sopenharmony_ci if (cmd_num < 0) 62162306a36Sopenharmony_ci return cmd_num; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci /* reo cmd ring descriptors has cmd_num starting from 1 */ 62462306a36Sopenharmony_ci if (cmd_num == 0) 62562306a36Sopenharmony_ci return -EINVAL; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if (!cb) 62862306a36Sopenharmony_ci return 0; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci /* Can this be optimized so that we keep the pending command list only 63162306a36Sopenharmony_ci * for tid delete command to free up the resource on the command status 63262306a36Sopenharmony_ci * indication? 63362306a36Sopenharmony_ci */ 63462306a36Sopenharmony_ci dp_cmd = kzalloc(sizeof(*dp_cmd), GFP_ATOMIC); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (!dp_cmd) 63762306a36Sopenharmony_ci return -ENOMEM; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci memcpy(&dp_cmd->data, rx_tid, sizeof(*rx_tid)); 64062306a36Sopenharmony_ci dp_cmd->cmd_num = cmd_num; 64162306a36Sopenharmony_ci dp_cmd->handler = cb; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci spin_lock_bh(&dp->reo_cmd_lock); 64462306a36Sopenharmony_ci list_add_tail(&dp_cmd->list, &dp->reo_cmd_list); 64562306a36Sopenharmony_ci spin_unlock_bh(&dp->reo_cmd_lock); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci return 0; 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cistatic void ath12k_dp_reo_cache_flush(struct ath12k_base *ab, 65162306a36Sopenharmony_ci struct ath12k_dp_rx_tid *rx_tid) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci struct ath12k_hal_reo_cmd cmd = {0}; 65462306a36Sopenharmony_ci unsigned long tot_desc_sz, desc_sz; 65562306a36Sopenharmony_ci int ret; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci tot_desc_sz = rx_tid->size; 65862306a36Sopenharmony_ci desc_sz = ath12k_hal_reo_qdesc_size(0, HAL_DESC_REO_NON_QOS_TID); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci while (tot_desc_sz > desc_sz) { 66162306a36Sopenharmony_ci tot_desc_sz -= desc_sz; 66262306a36Sopenharmony_ci cmd.addr_lo = lower_32_bits(rx_tid->paddr + tot_desc_sz); 66362306a36Sopenharmony_ci cmd.addr_hi = upper_32_bits(rx_tid->paddr); 66462306a36Sopenharmony_ci ret = ath12k_dp_reo_cmd_send(ab, rx_tid, 66562306a36Sopenharmony_ci HAL_REO_CMD_FLUSH_CACHE, &cmd, 66662306a36Sopenharmony_ci NULL); 66762306a36Sopenharmony_ci if (ret) 66862306a36Sopenharmony_ci ath12k_warn(ab, 66962306a36Sopenharmony_ci "failed to send HAL_REO_CMD_FLUSH_CACHE, tid %d (%d)\n", 67062306a36Sopenharmony_ci rx_tid->tid, ret); 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 67462306a36Sopenharmony_ci cmd.addr_lo = lower_32_bits(rx_tid->paddr); 67562306a36Sopenharmony_ci cmd.addr_hi = upper_32_bits(rx_tid->paddr); 67662306a36Sopenharmony_ci cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS; 67762306a36Sopenharmony_ci ret = ath12k_dp_reo_cmd_send(ab, rx_tid, 67862306a36Sopenharmony_ci HAL_REO_CMD_FLUSH_CACHE, 67962306a36Sopenharmony_ci &cmd, ath12k_dp_reo_cmd_free); 68062306a36Sopenharmony_ci if (ret) { 68162306a36Sopenharmony_ci ath12k_err(ab, "failed to send HAL_REO_CMD_FLUSH_CACHE cmd, tid %d (%d)\n", 68262306a36Sopenharmony_ci rx_tid->tid, ret); 68362306a36Sopenharmony_ci dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size, 68462306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 68562306a36Sopenharmony_ci kfree(rx_tid->vaddr); 68662306a36Sopenharmony_ci rx_tid->vaddr = NULL; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistatic void ath12k_dp_rx_tid_del_func(struct ath12k_dp *dp, void *ctx, 69162306a36Sopenharmony_ci enum hal_reo_cmd_status status) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci struct ath12k_base *ab = dp->ab; 69462306a36Sopenharmony_ci struct ath12k_dp_rx_tid *rx_tid = ctx; 69562306a36Sopenharmony_ci struct ath12k_dp_rx_reo_cache_flush_elem *elem, *tmp; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if (status == HAL_REO_CMD_DRAIN) { 69862306a36Sopenharmony_ci goto free_desc; 69962306a36Sopenharmony_ci } else if (status != HAL_REO_CMD_SUCCESS) { 70062306a36Sopenharmony_ci /* Shouldn't happen! Cleanup in case of other failure? */ 70162306a36Sopenharmony_ci ath12k_warn(ab, "failed to delete rx tid %d hw descriptor %d\n", 70262306a36Sopenharmony_ci rx_tid->tid, status); 70362306a36Sopenharmony_ci return; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci elem = kzalloc(sizeof(*elem), GFP_ATOMIC); 70762306a36Sopenharmony_ci if (!elem) 70862306a36Sopenharmony_ci goto free_desc; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci elem->ts = jiffies; 71162306a36Sopenharmony_ci memcpy(&elem->data, rx_tid, sizeof(*rx_tid)); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci spin_lock_bh(&dp->reo_cmd_lock); 71462306a36Sopenharmony_ci list_add_tail(&elem->list, &dp->reo_cmd_cache_flush_list); 71562306a36Sopenharmony_ci dp->reo_cmd_cache_flush_count++; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci /* Flush and invalidate aged REO desc from HW cache */ 71862306a36Sopenharmony_ci list_for_each_entry_safe(elem, tmp, &dp->reo_cmd_cache_flush_list, 71962306a36Sopenharmony_ci list) { 72062306a36Sopenharmony_ci if (dp->reo_cmd_cache_flush_count > ATH12K_DP_RX_REO_DESC_FREE_THRES || 72162306a36Sopenharmony_ci time_after(jiffies, elem->ts + 72262306a36Sopenharmony_ci msecs_to_jiffies(ATH12K_DP_RX_REO_DESC_FREE_TIMEOUT_MS))) { 72362306a36Sopenharmony_ci list_del(&elem->list); 72462306a36Sopenharmony_ci dp->reo_cmd_cache_flush_count--; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* Unlock the reo_cmd_lock before using ath12k_dp_reo_cmd_send() 72762306a36Sopenharmony_ci * within ath12k_dp_reo_cache_flush. The reo_cmd_cache_flush_list 72862306a36Sopenharmony_ci * is used in only two contexts, one is in this function called 72962306a36Sopenharmony_ci * from napi and the other in ath12k_dp_free during core destroy. 73062306a36Sopenharmony_ci * Before dp_free, the irqs would be disabled and would wait to 73162306a36Sopenharmony_ci * synchronize. Hence there wouldn’t be any race against add or 73262306a36Sopenharmony_ci * delete to this list. Hence unlock-lock is safe here. 73362306a36Sopenharmony_ci */ 73462306a36Sopenharmony_ci spin_unlock_bh(&dp->reo_cmd_lock); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci ath12k_dp_reo_cache_flush(ab, &elem->data); 73762306a36Sopenharmony_ci kfree(elem); 73862306a36Sopenharmony_ci spin_lock_bh(&dp->reo_cmd_lock); 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci spin_unlock_bh(&dp->reo_cmd_lock); 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci return; 74462306a36Sopenharmony_cifree_desc: 74562306a36Sopenharmony_ci dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size, 74662306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 74762306a36Sopenharmony_ci kfree(rx_tid->vaddr); 74862306a36Sopenharmony_ci rx_tid->vaddr = NULL; 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_cistatic void ath12k_peer_rx_tid_qref_setup(struct ath12k_base *ab, u16 peer_id, u16 tid, 75262306a36Sopenharmony_ci dma_addr_t paddr) 75362306a36Sopenharmony_ci{ 75462306a36Sopenharmony_ci struct ath12k_reo_queue_ref *qref; 75562306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci if (!ab->hw_params->reoq_lut_support) 75862306a36Sopenharmony_ci return; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci /* TODO: based on ML peer or not, select the LUT. below assumes non 76162306a36Sopenharmony_ci * ML peer 76262306a36Sopenharmony_ci */ 76362306a36Sopenharmony_ci qref = (struct ath12k_reo_queue_ref *)dp->reoq_lut.vaddr + 76462306a36Sopenharmony_ci (peer_id * (IEEE80211_NUM_TIDS + 1) + tid); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci qref->info0 = u32_encode_bits(lower_32_bits(paddr), 76762306a36Sopenharmony_ci BUFFER_ADDR_INFO0_ADDR); 76862306a36Sopenharmony_ci qref->info1 = u32_encode_bits(upper_32_bits(paddr), 76962306a36Sopenharmony_ci BUFFER_ADDR_INFO1_ADDR) | 77062306a36Sopenharmony_ci u32_encode_bits(tid, DP_REO_QREF_NUM); 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic void ath12k_peer_rx_tid_qref_reset(struct ath12k_base *ab, u16 peer_id, u16 tid) 77462306a36Sopenharmony_ci{ 77562306a36Sopenharmony_ci struct ath12k_reo_queue_ref *qref; 77662306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci if (!ab->hw_params->reoq_lut_support) 77962306a36Sopenharmony_ci return; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci /* TODO: based on ML peer or not, select the LUT. below assumes non 78262306a36Sopenharmony_ci * ML peer 78362306a36Sopenharmony_ci */ 78462306a36Sopenharmony_ci qref = (struct ath12k_reo_queue_ref *)dp->reoq_lut.vaddr + 78562306a36Sopenharmony_ci (peer_id * (IEEE80211_NUM_TIDS + 1) + tid); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci qref->info0 = u32_encode_bits(0, BUFFER_ADDR_INFO0_ADDR); 78862306a36Sopenharmony_ci qref->info1 = u32_encode_bits(0, BUFFER_ADDR_INFO1_ADDR) | 78962306a36Sopenharmony_ci u32_encode_bits(tid, DP_REO_QREF_NUM); 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_civoid ath12k_dp_rx_peer_tid_delete(struct ath12k *ar, 79362306a36Sopenharmony_ci struct ath12k_peer *peer, u8 tid) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci struct ath12k_hal_reo_cmd cmd = {0}; 79662306a36Sopenharmony_ci struct ath12k_dp_rx_tid *rx_tid = &peer->rx_tid[tid]; 79762306a36Sopenharmony_ci int ret; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci if (!rx_tid->active) 80062306a36Sopenharmony_ci return; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS; 80362306a36Sopenharmony_ci cmd.addr_lo = lower_32_bits(rx_tid->paddr); 80462306a36Sopenharmony_ci cmd.addr_hi = upper_32_bits(rx_tid->paddr); 80562306a36Sopenharmony_ci cmd.upd0 = HAL_REO_CMD_UPD0_VLD; 80662306a36Sopenharmony_ci ret = ath12k_dp_reo_cmd_send(ar->ab, rx_tid, 80762306a36Sopenharmony_ci HAL_REO_CMD_UPDATE_RX_QUEUE, &cmd, 80862306a36Sopenharmony_ci ath12k_dp_rx_tid_del_func); 80962306a36Sopenharmony_ci if (ret) { 81062306a36Sopenharmony_ci ath12k_err(ar->ab, "failed to send HAL_REO_CMD_UPDATE_RX_QUEUE cmd, tid %d (%d)\n", 81162306a36Sopenharmony_ci tid, ret); 81262306a36Sopenharmony_ci dma_unmap_single(ar->ab->dev, rx_tid->paddr, rx_tid->size, 81362306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 81462306a36Sopenharmony_ci kfree(rx_tid->vaddr); 81562306a36Sopenharmony_ci rx_tid->vaddr = NULL; 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci ath12k_peer_rx_tid_qref_reset(ar->ab, peer->peer_id, tid); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci rx_tid->active = false; 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci/* TODO: it's strange (and ugly) that struct hal_reo_dest_ring is converted 82462306a36Sopenharmony_ci * to struct hal_wbm_release_ring, I couldn't figure out the logic behind 82562306a36Sopenharmony_ci * that. 82662306a36Sopenharmony_ci */ 82762306a36Sopenharmony_cistatic int ath12k_dp_rx_link_desc_return(struct ath12k_base *ab, 82862306a36Sopenharmony_ci struct hal_reo_dest_ring *ring, 82962306a36Sopenharmony_ci enum hal_wbm_rel_bm_act action) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci struct hal_wbm_release_ring *link_desc = (struct hal_wbm_release_ring *)ring; 83262306a36Sopenharmony_ci struct hal_wbm_release_ring *desc; 83362306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 83462306a36Sopenharmony_ci struct hal_srng *srng; 83562306a36Sopenharmony_ci int ret = 0; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci srng = &ab->hal.srng_list[dp->wbm_desc_rel_ring.ring_id]; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci spin_lock_bh(&srng->lock); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci ath12k_hal_srng_access_begin(ab, srng); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci desc = ath12k_hal_srng_src_get_next_entry(ab, srng); 84462306a36Sopenharmony_ci if (!desc) { 84562306a36Sopenharmony_ci ret = -ENOBUFS; 84662306a36Sopenharmony_ci goto exit; 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci ath12k_hal_rx_msdu_link_desc_set(ab, desc, link_desc, action); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ciexit: 85262306a36Sopenharmony_ci ath12k_hal_srng_access_end(ab, srng); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci spin_unlock_bh(&srng->lock); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci return ret; 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_cistatic void ath12k_dp_rx_frags_cleanup(struct ath12k_dp_rx_tid *rx_tid, 86062306a36Sopenharmony_ci bool rel_link_desc) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci struct ath12k_base *ab = rx_tid->ab; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci lockdep_assert_held(&ab->base_lock); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci if (rx_tid->dst_ring_desc) { 86762306a36Sopenharmony_ci if (rel_link_desc) 86862306a36Sopenharmony_ci ath12k_dp_rx_link_desc_return(ab, rx_tid->dst_ring_desc, 86962306a36Sopenharmony_ci HAL_WBM_REL_BM_ACT_PUT_IN_IDLE); 87062306a36Sopenharmony_ci kfree(rx_tid->dst_ring_desc); 87162306a36Sopenharmony_ci rx_tid->dst_ring_desc = NULL; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci rx_tid->cur_sn = 0; 87562306a36Sopenharmony_ci rx_tid->last_frag_no = 0; 87662306a36Sopenharmony_ci rx_tid->rx_frag_bitmap = 0; 87762306a36Sopenharmony_ci __skb_queue_purge(&rx_tid->rx_frags); 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_civoid ath12k_dp_rx_peer_tid_cleanup(struct ath12k *ar, struct ath12k_peer *peer) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci struct ath12k_dp_rx_tid *rx_tid; 88362306a36Sopenharmony_ci int i; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci lockdep_assert_held(&ar->ab->base_lock); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci for (i = 0; i <= IEEE80211_NUM_TIDS; i++) { 88862306a36Sopenharmony_ci rx_tid = &peer->rx_tid[i]; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci ath12k_dp_rx_peer_tid_delete(ar, peer, i); 89162306a36Sopenharmony_ci ath12k_dp_rx_frags_cleanup(rx_tid, true); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci spin_unlock_bh(&ar->ab->base_lock); 89462306a36Sopenharmony_ci del_timer_sync(&rx_tid->frag_timer); 89562306a36Sopenharmony_ci spin_lock_bh(&ar->ab->base_lock); 89662306a36Sopenharmony_ci } 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_cistatic int ath12k_peer_rx_tid_reo_update(struct ath12k *ar, 90062306a36Sopenharmony_ci struct ath12k_peer *peer, 90162306a36Sopenharmony_ci struct ath12k_dp_rx_tid *rx_tid, 90262306a36Sopenharmony_ci u32 ba_win_sz, u16 ssn, 90362306a36Sopenharmony_ci bool update_ssn) 90462306a36Sopenharmony_ci{ 90562306a36Sopenharmony_ci struct ath12k_hal_reo_cmd cmd = {0}; 90662306a36Sopenharmony_ci int ret; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci cmd.addr_lo = lower_32_bits(rx_tid->paddr); 90962306a36Sopenharmony_ci cmd.addr_hi = upper_32_bits(rx_tid->paddr); 91062306a36Sopenharmony_ci cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS; 91162306a36Sopenharmony_ci cmd.upd0 = HAL_REO_CMD_UPD0_BA_WINDOW_SIZE; 91262306a36Sopenharmony_ci cmd.ba_window_size = ba_win_sz; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci if (update_ssn) { 91562306a36Sopenharmony_ci cmd.upd0 |= HAL_REO_CMD_UPD0_SSN; 91662306a36Sopenharmony_ci cmd.upd2 = u32_encode_bits(ssn, HAL_REO_CMD_UPD2_SSN); 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci ret = ath12k_dp_reo_cmd_send(ar->ab, rx_tid, 92062306a36Sopenharmony_ci HAL_REO_CMD_UPDATE_RX_QUEUE, &cmd, 92162306a36Sopenharmony_ci NULL); 92262306a36Sopenharmony_ci if (ret) { 92362306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to update rx tid queue, tid %d (%d)\n", 92462306a36Sopenharmony_ci rx_tid->tid, ret); 92562306a36Sopenharmony_ci return ret; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci rx_tid->ba_win_sz = ba_win_sz; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci return 0; 93162306a36Sopenharmony_ci} 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ciint ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_id, 93462306a36Sopenharmony_ci u8 tid, u32 ba_win_sz, u16 ssn, 93562306a36Sopenharmony_ci enum hal_pn_type pn_type) 93662306a36Sopenharmony_ci{ 93762306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 93862306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 93962306a36Sopenharmony_ci struct hal_rx_reo_queue *addr_aligned; 94062306a36Sopenharmony_ci struct ath12k_peer *peer; 94162306a36Sopenharmony_ci struct ath12k_dp_rx_tid *rx_tid; 94262306a36Sopenharmony_ci u32 hw_desc_sz; 94362306a36Sopenharmony_ci void *vaddr; 94462306a36Sopenharmony_ci dma_addr_t paddr; 94562306a36Sopenharmony_ci int ret; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci spin_lock_bh(&ab->base_lock); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci peer = ath12k_peer_find(ab, vdev_id, peer_mac); 95062306a36Sopenharmony_ci if (!peer) { 95162306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 95262306a36Sopenharmony_ci ath12k_warn(ab, "failed to find the peer to set up rx tid\n"); 95362306a36Sopenharmony_ci return -ENOENT; 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci if (ab->hw_params->reoq_lut_support && !dp->reoq_lut.vaddr) { 95762306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 95862306a36Sopenharmony_ci ath12k_warn(ab, "reo qref table is not setup\n"); 95962306a36Sopenharmony_ci return -EINVAL; 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci if (peer->peer_id > DP_MAX_PEER_ID || tid > IEEE80211_NUM_TIDS) { 96362306a36Sopenharmony_ci ath12k_warn(ab, "peer id of peer %d or tid %d doesn't allow reoq setup\n", 96462306a36Sopenharmony_ci peer->peer_id, tid); 96562306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 96662306a36Sopenharmony_ci return -EINVAL; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci rx_tid = &peer->rx_tid[tid]; 97062306a36Sopenharmony_ci /* Update the tid queue if it is already setup */ 97162306a36Sopenharmony_ci if (rx_tid->active) { 97262306a36Sopenharmony_ci paddr = rx_tid->paddr; 97362306a36Sopenharmony_ci ret = ath12k_peer_rx_tid_reo_update(ar, peer, rx_tid, 97462306a36Sopenharmony_ci ba_win_sz, ssn, true); 97562306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 97662306a36Sopenharmony_ci if (ret) { 97762306a36Sopenharmony_ci ath12k_warn(ab, "failed to update reo for rx tid %d\n", tid); 97862306a36Sopenharmony_ci return ret; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci if (!ab->hw_params->reoq_lut_support) { 98262306a36Sopenharmony_ci ret = ath12k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, 98362306a36Sopenharmony_ci peer_mac, 98462306a36Sopenharmony_ci paddr, tid, 1, 98562306a36Sopenharmony_ci ba_win_sz); 98662306a36Sopenharmony_ci if (ret) { 98762306a36Sopenharmony_ci ath12k_warn(ab, "failed to setup peer rx reorder queuefor tid %d: %d\n", 98862306a36Sopenharmony_ci tid, ret); 98962306a36Sopenharmony_ci return ret; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci return 0; 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci rx_tid->tid = tid; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci rx_tid->ba_win_sz = ba_win_sz; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci /* TODO: Optimize the memory allocation for qos tid based on 100162306a36Sopenharmony_ci * the actual BA window size in REO tid update path. 100262306a36Sopenharmony_ci */ 100362306a36Sopenharmony_ci if (tid == HAL_DESC_REO_NON_QOS_TID) 100462306a36Sopenharmony_ci hw_desc_sz = ath12k_hal_reo_qdesc_size(ba_win_sz, tid); 100562306a36Sopenharmony_ci else 100662306a36Sopenharmony_ci hw_desc_sz = ath12k_hal_reo_qdesc_size(DP_BA_WIN_SZ_MAX, tid); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci vaddr = kzalloc(hw_desc_sz + HAL_LINK_DESC_ALIGN - 1, GFP_ATOMIC); 100962306a36Sopenharmony_ci if (!vaddr) { 101062306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 101162306a36Sopenharmony_ci return -ENOMEM; 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci addr_aligned = PTR_ALIGN(vaddr, HAL_LINK_DESC_ALIGN); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci ath12k_hal_reo_qdesc_setup(addr_aligned, tid, ba_win_sz, 101762306a36Sopenharmony_ci ssn, pn_type); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci paddr = dma_map_single(ab->dev, addr_aligned, hw_desc_sz, 102062306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci ret = dma_mapping_error(ab->dev, paddr); 102362306a36Sopenharmony_ci if (ret) { 102462306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 102562306a36Sopenharmony_ci goto err_mem_free; 102662306a36Sopenharmony_ci } 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci rx_tid->vaddr = vaddr; 102962306a36Sopenharmony_ci rx_tid->paddr = paddr; 103062306a36Sopenharmony_ci rx_tid->size = hw_desc_sz; 103162306a36Sopenharmony_ci rx_tid->active = true; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci if (ab->hw_params->reoq_lut_support) { 103462306a36Sopenharmony_ci /* Update the REO queue LUT at the corresponding peer id 103562306a36Sopenharmony_ci * and tid with qaddr. 103662306a36Sopenharmony_ci */ 103762306a36Sopenharmony_ci ath12k_peer_rx_tid_qref_setup(ab, peer->peer_id, tid, paddr); 103862306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 103962306a36Sopenharmony_ci } else { 104062306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 104162306a36Sopenharmony_ci ret = ath12k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, peer_mac, 104262306a36Sopenharmony_ci paddr, tid, 1, ba_win_sz); 104362306a36Sopenharmony_ci } 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci return ret; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_cierr_mem_free: 104862306a36Sopenharmony_ci kfree(vaddr); 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci return ret; 105162306a36Sopenharmony_ci} 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ciint ath12k_dp_rx_ampdu_start(struct ath12k *ar, 105462306a36Sopenharmony_ci struct ieee80211_ampdu_params *params) 105562306a36Sopenharmony_ci{ 105662306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 105762306a36Sopenharmony_ci struct ath12k_sta *arsta = (void *)params->sta->drv_priv; 105862306a36Sopenharmony_ci int vdev_id = arsta->arvif->vdev_id; 105962306a36Sopenharmony_ci int ret; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci ret = ath12k_dp_rx_peer_tid_setup(ar, params->sta->addr, vdev_id, 106262306a36Sopenharmony_ci params->tid, params->buf_size, 106362306a36Sopenharmony_ci params->ssn, arsta->pn_type); 106462306a36Sopenharmony_ci if (ret) 106562306a36Sopenharmony_ci ath12k_warn(ab, "failed to setup rx tid %d\n", ret); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci return ret; 106862306a36Sopenharmony_ci} 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ciint ath12k_dp_rx_ampdu_stop(struct ath12k *ar, 107162306a36Sopenharmony_ci struct ieee80211_ampdu_params *params) 107262306a36Sopenharmony_ci{ 107362306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 107462306a36Sopenharmony_ci struct ath12k_peer *peer; 107562306a36Sopenharmony_ci struct ath12k_sta *arsta = (void *)params->sta->drv_priv; 107662306a36Sopenharmony_ci int vdev_id = arsta->arvif->vdev_id; 107762306a36Sopenharmony_ci bool active; 107862306a36Sopenharmony_ci int ret; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci spin_lock_bh(&ab->base_lock); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci peer = ath12k_peer_find(ab, vdev_id, params->sta->addr); 108362306a36Sopenharmony_ci if (!peer) { 108462306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 108562306a36Sopenharmony_ci ath12k_warn(ab, "failed to find the peer to stop rx aggregation\n"); 108662306a36Sopenharmony_ci return -ENOENT; 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci active = peer->rx_tid[params->tid].active; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci if (!active) { 109262306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 109362306a36Sopenharmony_ci return 0; 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci ret = ath12k_peer_rx_tid_reo_update(ar, peer, peer->rx_tid, 1, 0, false); 109762306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 109862306a36Sopenharmony_ci if (ret) { 109962306a36Sopenharmony_ci ath12k_warn(ab, "failed to update reo for rx tid %d: %d\n", 110062306a36Sopenharmony_ci params->tid, ret); 110162306a36Sopenharmony_ci return ret; 110262306a36Sopenharmony_ci } 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci return ret; 110562306a36Sopenharmony_ci} 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ciint ath12k_dp_rx_peer_pn_replay_config(struct ath12k_vif *arvif, 110862306a36Sopenharmony_ci const u8 *peer_addr, 110962306a36Sopenharmony_ci enum set_key_cmd key_cmd, 111062306a36Sopenharmony_ci struct ieee80211_key_conf *key) 111162306a36Sopenharmony_ci{ 111262306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 111362306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 111462306a36Sopenharmony_ci struct ath12k_hal_reo_cmd cmd = {0}; 111562306a36Sopenharmony_ci struct ath12k_peer *peer; 111662306a36Sopenharmony_ci struct ath12k_dp_rx_tid *rx_tid; 111762306a36Sopenharmony_ci u8 tid; 111862306a36Sopenharmony_ci int ret = 0; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci /* NOTE: Enable PN/TSC replay check offload only for unicast frames. 112162306a36Sopenharmony_ci * We use mac80211 PN/TSC replay check functionality for bcast/mcast 112262306a36Sopenharmony_ci * for now. 112362306a36Sopenharmony_ci */ 112462306a36Sopenharmony_ci if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 112562306a36Sopenharmony_ci return 0; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS; 112862306a36Sopenharmony_ci cmd.upd0 = HAL_REO_CMD_UPD0_PN | 112962306a36Sopenharmony_ci HAL_REO_CMD_UPD0_PN_SIZE | 113062306a36Sopenharmony_ci HAL_REO_CMD_UPD0_PN_VALID | 113162306a36Sopenharmony_ci HAL_REO_CMD_UPD0_PN_CHECK | 113262306a36Sopenharmony_ci HAL_REO_CMD_UPD0_SVLD; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci switch (key->cipher) { 113562306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 113662306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 113762306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP_256: 113862306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP: 113962306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP_256: 114062306a36Sopenharmony_ci if (key_cmd == SET_KEY) { 114162306a36Sopenharmony_ci cmd.upd1 |= HAL_REO_CMD_UPD1_PN_CHECK; 114262306a36Sopenharmony_ci cmd.pn_size = 48; 114362306a36Sopenharmony_ci } 114462306a36Sopenharmony_ci break; 114562306a36Sopenharmony_ci default: 114662306a36Sopenharmony_ci break; 114762306a36Sopenharmony_ci } 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci spin_lock_bh(&ab->base_lock); 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci peer = ath12k_peer_find(ab, arvif->vdev_id, peer_addr); 115262306a36Sopenharmony_ci if (!peer) { 115362306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 115462306a36Sopenharmony_ci ath12k_warn(ab, "failed to find the peer %pM to configure pn replay detection\n", 115562306a36Sopenharmony_ci peer_addr); 115662306a36Sopenharmony_ci return -ENOENT; 115762306a36Sopenharmony_ci } 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci for (tid = 0; tid <= IEEE80211_NUM_TIDS; tid++) { 116062306a36Sopenharmony_ci rx_tid = &peer->rx_tid[tid]; 116162306a36Sopenharmony_ci if (!rx_tid->active) 116262306a36Sopenharmony_ci continue; 116362306a36Sopenharmony_ci cmd.addr_lo = lower_32_bits(rx_tid->paddr); 116462306a36Sopenharmony_ci cmd.addr_hi = upper_32_bits(rx_tid->paddr); 116562306a36Sopenharmony_ci ret = ath12k_dp_reo_cmd_send(ab, rx_tid, 116662306a36Sopenharmony_ci HAL_REO_CMD_UPDATE_RX_QUEUE, 116762306a36Sopenharmony_ci &cmd, NULL); 116862306a36Sopenharmony_ci if (ret) { 116962306a36Sopenharmony_ci ath12k_warn(ab, "failed to configure rx tid %d queue of peer %pM for pn replay detection %d\n", 117062306a36Sopenharmony_ci tid, peer_addr, ret); 117162306a36Sopenharmony_ci break; 117262306a36Sopenharmony_ci } 117362306a36Sopenharmony_ci } 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci return ret; 117862306a36Sopenharmony_ci} 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_cistatic int ath12k_get_ppdu_user_index(struct htt_ppdu_stats *ppdu_stats, 118162306a36Sopenharmony_ci u16 peer_id) 118262306a36Sopenharmony_ci{ 118362306a36Sopenharmony_ci int i; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci for (i = 0; i < HTT_PPDU_STATS_MAX_USERS - 1; i++) { 118662306a36Sopenharmony_ci if (ppdu_stats->user_stats[i].is_valid_peer_id) { 118762306a36Sopenharmony_ci if (peer_id == ppdu_stats->user_stats[i].peer_id) 118862306a36Sopenharmony_ci return i; 118962306a36Sopenharmony_ci } else { 119062306a36Sopenharmony_ci return i; 119162306a36Sopenharmony_ci } 119262306a36Sopenharmony_ci } 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci return -EINVAL; 119562306a36Sopenharmony_ci} 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_cistatic int ath12k_htt_tlv_ppdu_stats_parse(struct ath12k_base *ab, 119862306a36Sopenharmony_ci u16 tag, u16 len, const void *ptr, 119962306a36Sopenharmony_ci void *data) 120062306a36Sopenharmony_ci{ 120162306a36Sopenharmony_ci const struct htt_ppdu_stats_usr_cmpltn_ack_ba_status *ba_status; 120262306a36Sopenharmony_ci const struct htt_ppdu_stats_usr_cmpltn_cmn *cmplt_cmn; 120362306a36Sopenharmony_ci const struct htt_ppdu_stats_user_rate *user_rate; 120462306a36Sopenharmony_ci struct htt_ppdu_stats_info *ppdu_info; 120562306a36Sopenharmony_ci struct htt_ppdu_user_stats *user_stats; 120662306a36Sopenharmony_ci int cur_user; 120762306a36Sopenharmony_ci u16 peer_id; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci ppdu_info = data; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci switch (tag) { 121262306a36Sopenharmony_ci case HTT_PPDU_STATS_TAG_COMMON: 121362306a36Sopenharmony_ci if (len < sizeof(struct htt_ppdu_stats_common)) { 121462306a36Sopenharmony_ci ath12k_warn(ab, "Invalid len %d for the tag 0x%x\n", 121562306a36Sopenharmony_ci len, tag); 121662306a36Sopenharmony_ci return -EINVAL; 121762306a36Sopenharmony_ci } 121862306a36Sopenharmony_ci memcpy(&ppdu_info->ppdu_stats.common, ptr, 121962306a36Sopenharmony_ci sizeof(struct htt_ppdu_stats_common)); 122062306a36Sopenharmony_ci break; 122162306a36Sopenharmony_ci case HTT_PPDU_STATS_TAG_USR_RATE: 122262306a36Sopenharmony_ci if (len < sizeof(struct htt_ppdu_stats_user_rate)) { 122362306a36Sopenharmony_ci ath12k_warn(ab, "Invalid len %d for the tag 0x%x\n", 122462306a36Sopenharmony_ci len, tag); 122562306a36Sopenharmony_ci return -EINVAL; 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci user_rate = ptr; 122862306a36Sopenharmony_ci peer_id = le16_to_cpu(user_rate->sw_peer_id); 122962306a36Sopenharmony_ci cur_user = ath12k_get_ppdu_user_index(&ppdu_info->ppdu_stats, 123062306a36Sopenharmony_ci peer_id); 123162306a36Sopenharmony_ci if (cur_user < 0) 123262306a36Sopenharmony_ci return -EINVAL; 123362306a36Sopenharmony_ci user_stats = &ppdu_info->ppdu_stats.user_stats[cur_user]; 123462306a36Sopenharmony_ci user_stats->peer_id = peer_id; 123562306a36Sopenharmony_ci user_stats->is_valid_peer_id = true; 123662306a36Sopenharmony_ci memcpy(&user_stats->rate, ptr, 123762306a36Sopenharmony_ci sizeof(struct htt_ppdu_stats_user_rate)); 123862306a36Sopenharmony_ci user_stats->tlv_flags |= BIT(tag); 123962306a36Sopenharmony_ci break; 124062306a36Sopenharmony_ci case HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON: 124162306a36Sopenharmony_ci if (len < sizeof(struct htt_ppdu_stats_usr_cmpltn_cmn)) { 124262306a36Sopenharmony_ci ath12k_warn(ab, "Invalid len %d for the tag 0x%x\n", 124362306a36Sopenharmony_ci len, tag); 124462306a36Sopenharmony_ci return -EINVAL; 124562306a36Sopenharmony_ci } 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci cmplt_cmn = ptr; 124862306a36Sopenharmony_ci peer_id = le16_to_cpu(cmplt_cmn->sw_peer_id); 124962306a36Sopenharmony_ci cur_user = ath12k_get_ppdu_user_index(&ppdu_info->ppdu_stats, 125062306a36Sopenharmony_ci peer_id); 125162306a36Sopenharmony_ci if (cur_user < 0) 125262306a36Sopenharmony_ci return -EINVAL; 125362306a36Sopenharmony_ci user_stats = &ppdu_info->ppdu_stats.user_stats[cur_user]; 125462306a36Sopenharmony_ci user_stats->peer_id = peer_id; 125562306a36Sopenharmony_ci user_stats->is_valid_peer_id = true; 125662306a36Sopenharmony_ci memcpy(&user_stats->cmpltn_cmn, ptr, 125762306a36Sopenharmony_ci sizeof(struct htt_ppdu_stats_usr_cmpltn_cmn)); 125862306a36Sopenharmony_ci user_stats->tlv_flags |= BIT(tag); 125962306a36Sopenharmony_ci break; 126062306a36Sopenharmony_ci case HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS: 126162306a36Sopenharmony_ci if (len < 126262306a36Sopenharmony_ci sizeof(struct htt_ppdu_stats_usr_cmpltn_ack_ba_status)) { 126362306a36Sopenharmony_ci ath12k_warn(ab, "Invalid len %d for the tag 0x%x\n", 126462306a36Sopenharmony_ci len, tag); 126562306a36Sopenharmony_ci return -EINVAL; 126662306a36Sopenharmony_ci } 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci ba_status = ptr; 126962306a36Sopenharmony_ci peer_id = le16_to_cpu(ba_status->sw_peer_id); 127062306a36Sopenharmony_ci cur_user = ath12k_get_ppdu_user_index(&ppdu_info->ppdu_stats, 127162306a36Sopenharmony_ci peer_id); 127262306a36Sopenharmony_ci if (cur_user < 0) 127362306a36Sopenharmony_ci return -EINVAL; 127462306a36Sopenharmony_ci user_stats = &ppdu_info->ppdu_stats.user_stats[cur_user]; 127562306a36Sopenharmony_ci user_stats->peer_id = peer_id; 127662306a36Sopenharmony_ci user_stats->is_valid_peer_id = true; 127762306a36Sopenharmony_ci memcpy(&user_stats->ack_ba, ptr, 127862306a36Sopenharmony_ci sizeof(struct htt_ppdu_stats_usr_cmpltn_ack_ba_status)); 127962306a36Sopenharmony_ci user_stats->tlv_flags |= BIT(tag); 128062306a36Sopenharmony_ci break; 128162306a36Sopenharmony_ci } 128262306a36Sopenharmony_ci return 0; 128362306a36Sopenharmony_ci} 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_cistatic int ath12k_dp_htt_tlv_iter(struct ath12k_base *ab, const void *ptr, size_t len, 128662306a36Sopenharmony_ci int (*iter)(struct ath12k_base *ar, u16 tag, u16 len, 128762306a36Sopenharmony_ci const void *ptr, void *data), 128862306a36Sopenharmony_ci void *data) 128962306a36Sopenharmony_ci{ 129062306a36Sopenharmony_ci const struct htt_tlv *tlv; 129162306a36Sopenharmony_ci const void *begin = ptr; 129262306a36Sopenharmony_ci u16 tlv_tag, tlv_len; 129362306a36Sopenharmony_ci int ret = -EINVAL; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci while (len > 0) { 129662306a36Sopenharmony_ci if (len < sizeof(*tlv)) { 129762306a36Sopenharmony_ci ath12k_err(ab, "htt tlv parse failure at byte %zd (%zu bytes left, %zu expected)\n", 129862306a36Sopenharmony_ci ptr - begin, len, sizeof(*tlv)); 129962306a36Sopenharmony_ci return -EINVAL; 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci tlv = (struct htt_tlv *)ptr; 130262306a36Sopenharmony_ci tlv_tag = le32_get_bits(tlv->header, HTT_TLV_TAG); 130362306a36Sopenharmony_ci tlv_len = le32_get_bits(tlv->header, HTT_TLV_LEN); 130462306a36Sopenharmony_ci ptr += sizeof(*tlv); 130562306a36Sopenharmony_ci len -= sizeof(*tlv); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci if (tlv_len > len) { 130862306a36Sopenharmony_ci ath12k_err(ab, "htt tlv parse failure of tag %u at byte %zd (%zu bytes left, %u expected)\n", 130962306a36Sopenharmony_ci tlv_tag, ptr - begin, len, tlv_len); 131062306a36Sopenharmony_ci return -EINVAL; 131162306a36Sopenharmony_ci } 131262306a36Sopenharmony_ci ret = iter(ab, tlv_tag, tlv_len, ptr, data); 131362306a36Sopenharmony_ci if (ret == -ENOMEM) 131462306a36Sopenharmony_ci return ret; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci ptr += tlv_len; 131762306a36Sopenharmony_ci len -= tlv_len; 131862306a36Sopenharmony_ci } 131962306a36Sopenharmony_ci return 0; 132062306a36Sopenharmony_ci} 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_cistatic void 132362306a36Sopenharmony_ciath12k_update_per_peer_tx_stats(struct ath12k *ar, 132462306a36Sopenharmony_ci struct htt_ppdu_stats *ppdu_stats, u8 user) 132562306a36Sopenharmony_ci{ 132662306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 132762306a36Sopenharmony_ci struct ath12k_peer *peer; 132862306a36Sopenharmony_ci struct ieee80211_sta *sta; 132962306a36Sopenharmony_ci struct ath12k_sta *arsta; 133062306a36Sopenharmony_ci struct htt_ppdu_stats_user_rate *user_rate; 133162306a36Sopenharmony_ci struct ath12k_per_peer_tx_stats *peer_stats = &ar->peer_tx_stats; 133262306a36Sopenharmony_ci struct htt_ppdu_user_stats *usr_stats = &ppdu_stats->user_stats[user]; 133362306a36Sopenharmony_ci struct htt_ppdu_stats_common *common = &ppdu_stats->common; 133462306a36Sopenharmony_ci int ret; 133562306a36Sopenharmony_ci u8 flags, mcs, nss, bw, sgi, dcm, rate_idx = 0; 133662306a36Sopenharmony_ci u32 v, succ_bytes = 0; 133762306a36Sopenharmony_ci u16 tones, rate = 0, succ_pkts = 0; 133862306a36Sopenharmony_ci u32 tx_duration = 0; 133962306a36Sopenharmony_ci u8 tid = HTT_PPDU_STATS_NON_QOS_TID; 134062306a36Sopenharmony_ci bool is_ampdu = false; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci if (!usr_stats) 134362306a36Sopenharmony_ci return; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci if (!(usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_RATE))) 134662306a36Sopenharmony_ci return; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON)) 134962306a36Sopenharmony_ci is_ampdu = 135062306a36Sopenharmony_ci HTT_USR_CMPLTN_IS_AMPDU(usr_stats->cmpltn_cmn.flags); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci if (usr_stats->tlv_flags & 135362306a36Sopenharmony_ci BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS)) { 135462306a36Sopenharmony_ci succ_bytes = le32_to_cpu(usr_stats->ack_ba.success_bytes); 135562306a36Sopenharmony_ci succ_pkts = le32_get_bits(usr_stats->ack_ba.info, 135662306a36Sopenharmony_ci HTT_PPDU_STATS_ACK_BA_INFO_NUM_MSDU_M); 135762306a36Sopenharmony_ci tid = le32_get_bits(usr_stats->ack_ba.info, 135862306a36Sopenharmony_ci HTT_PPDU_STATS_ACK_BA_INFO_TID_NUM); 135962306a36Sopenharmony_ci } 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci if (common->fes_duration_us) 136262306a36Sopenharmony_ci tx_duration = le32_to_cpu(common->fes_duration_us); 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci user_rate = &usr_stats->rate; 136562306a36Sopenharmony_ci flags = HTT_USR_RATE_PREAMBLE(user_rate->rate_flags); 136662306a36Sopenharmony_ci bw = HTT_USR_RATE_BW(user_rate->rate_flags) - 2; 136762306a36Sopenharmony_ci nss = HTT_USR_RATE_NSS(user_rate->rate_flags) + 1; 136862306a36Sopenharmony_ci mcs = HTT_USR_RATE_MCS(user_rate->rate_flags); 136962306a36Sopenharmony_ci sgi = HTT_USR_RATE_GI(user_rate->rate_flags); 137062306a36Sopenharmony_ci dcm = HTT_USR_RATE_DCM(user_rate->rate_flags); 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci /* Note: If host configured fixed rates and in some other special 137362306a36Sopenharmony_ci * cases, the broadcast/management frames are sent in different rates. 137462306a36Sopenharmony_ci * Firmware rate's control to be skipped for this? 137562306a36Sopenharmony_ci */ 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci if (flags == WMI_RATE_PREAMBLE_HE && mcs > ATH12K_HE_MCS_MAX) { 137862306a36Sopenharmony_ci ath12k_warn(ab, "Invalid HE mcs %d peer stats", mcs); 137962306a36Sopenharmony_ci return; 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci if (flags == WMI_RATE_PREAMBLE_VHT && mcs > ATH12K_VHT_MCS_MAX) { 138362306a36Sopenharmony_ci ath12k_warn(ab, "Invalid VHT mcs %d peer stats", mcs); 138462306a36Sopenharmony_ci return; 138562306a36Sopenharmony_ci } 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci if (flags == WMI_RATE_PREAMBLE_HT && (mcs > ATH12K_HT_MCS_MAX || nss < 1)) { 138862306a36Sopenharmony_ci ath12k_warn(ab, "Invalid HT mcs %d nss %d peer stats", 138962306a36Sopenharmony_ci mcs, nss); 139062306a36Sopenharmony_ci return; 139162306a36Sopenharmony_ci } 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci if (flags == WMI_RATE_PREAMBLE_CCK || flags == WMI_RATE_PREAMBLE_OFDM) { 139462306a36Sopenharmony_ci ret = ath12k_mac_hw_ratecode_to_legacy_rate(mcs, 139562306a36Sopenharmony_ci flags, 139662306a36Sopenharmony_ci &rate_idx, 139762306a36Sopenharmony_ci &rate); 139862306a36Sopenharmony_ci if (ret < 0) 139962306a36Sopenharmony_ci return; 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci rcu_read_lock(); 140362306a36Sopenharmony_ci spin_lock_bh(&ab->base_lock); 140462306a36Sopenharmony_ci peer = ath12k_peer_find_by_id(ab, usr_stats->peer_id); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci if (!peer || !peer->sta) { 140762306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 140862306a36Sopenharmony_ci rcu_read_unlock(); 140962306a36Sopenharmony_ci return; 141062306a36Sopenharmony_ci } 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci sta = peer->sta; 141362306a36Sopenharmony_ci arsta = (struct ath12k_sta *)sta->drv_priv; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci memset(&arsta->txrate, 0, sizeof(arsta->txrate)); 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci switch (flags) { 141862306a36Sopenharmony_ci case WMI_RATE_PREAMBLE_OFDM: 141962306a36Sopenharmony_ci arsta->txrate.legacy = rate; 142062306a36Sopenharmony_ci break; 142162306a36Sopenharmony_ci case WMI_RATE_PREAMBLE_CCK: 142262306a36Sopenharmony_ci arsta->txrate.legacy = rate; 142362306a36Sopenharmony_ci break; 142462306a36Sopenharmony_ci case WMI_RATE_PREAMBLE_HT: 142562306a36Sopenharmony_ci arsta->txrate.mcs = mcs + 8 * (nss - 1); 142662306a36Sopenharmony_ci arsta->txrate.flags = RATE_INFO_FLAGS_MCS; 142762306a36Sopenharmony_ci if (sgi) 142862306a36Sopenharmony_ci arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; 142962306a36Sopenharmony_ci break; 143062306a36Sopenharmony_ci case WMI_RATE_PREAMBLE_VHT: 143162306a36Sopenharmony_ci arsta->txrate.mcs = mcs; 143262306a36Sopenharmony_ci arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS; 143362306a36Sopenharmony_ci if (sgi) 143462306a36Sopenharmony_ci arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; 143562306a36Sopenharmony_ci break; 143662306a36Sopenharmony_ci case WMI_RATE_PREAMBLE_HE: 143762306a36Sopenharmony_ci arsta->txrate.mcs = mcs; 143862306a36Sopenharmony_ci arsta->txrate.flags = RATE_INFO_FLAGS_HE_MCS; 143962306a36Sopenharmony_ci arsta->txrate.he_dcm = dcm; 144062306a36Sopenharmony_ci arsta->txrate.he_gi = ath12k_he_gi_to_nl80211_he_gi(sgi); 144162306a36Sopenharmony_ci tones = le16_to_cpu(user_rate->ru_end) - 144262306a36Sopenharmony_ci le16_to_cpu(user_rate->ru_start) + 1; 144362306a36Sopenharmony_ci v = ath12k_he_ru_tones_to_nl80211_he_ru_alloc(tones); 144462306a36Sopenharmony_ci arsta->txrate.he_ru_alloc = v; 144562306a36Sopenharmony_ci break; 144662306a36Sopenharmony_ci } 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci arsta->txrate.nss = nss; 144962306a36Sopenharmony_ci arsta->txrate.bw = ath12k_mac_bw_to_mac80211_bw(bw); 145062306a36Sopenharmony_ci arsta->tx_duration += tx_duration; 145162306a36Sopenharmony_ci memcpy(&arsta->last_txrate, &arsta->txrate, sizeof(struct rate_info)); 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci /* PPDU stats reported for mgmt packet doesn't have valid tx bytes. 145462306a36Sopenharmony_ci * So skip peer stats update for mgmt packets. 145562306a36Sopenharmony_ci */ 145662306a36Sopenharmony_ci if (tid < HTT_PPDU_STATS_NON_QOS_TID) { 145762306a36Sopenharmony_ci memset(peer_stats, 0, sizeof(*peer_stats)); 145862306a36Sopenharmony_ci peer_stats->succ_pkts = succ_pkts; 145962306a36Sopenharmony_ci peer_stats->succ_bytes = succ_bytes; 146062306a36Sopenharmony_ci peer_stats->is_ampdu = is_ampdu; 146162306a36Sopenharmony_ci peer_stats->duration = tx_duration; 146262306a36Sopenharmony_ci peer_stats->ba_fails = 146362306a36Sopenharmony_ci HTT_USR_CMPLTN_LONG_RETRY(usr_stats->cmpltn_cmn.flags) + 146462306a36Sopenharmony_ci HTT_USR_CMPLTN_SHORT_RETRY(usr_stats->cmpltn_cmn.flags); 146562306a36Sopenharmony_ci } 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 146862306a36Sopenharmony_ci rcu_read_unlock(); 146962306a36Sopenharmony_ci} 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_cistatic void ath12k_htt_update_ppdu_stats(struct ath12k *ar, 147262306a36Sopenharmony_ci struct htt_ppdu_stats *ppdu_stats) 147362306a36Sopenharmony_ci{ 147462306a36Sopenharmony_ci u8 user; 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci for (user = 0; user < HTT_PPDU_STATS_MAX_USERS - 1; user++) 147762306a36Sopenharmony_ci ath12k_update_per_peer_tx_stats(ar, ppdu_stats, user); 147862306a36Sopenharmony_ci} 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_cistatic 148162306a36Sopenharmony_cistruct htt_ppdu_stats_info *ath12k_dp_htt_get_ppdu_desc(struct ath12k *ar, 148262306a36Sopenharmony_ci u32 ppdu_id) 148362306a36Sopenharmony_ci{ 148462306a36Sopenharmony_ci struct htt_ppdu_stats_info *ppdu_info; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci lockdep_assert_held(&ar->data_lock); 148762306a36Sopenharmony_ci if (!list_empty(&ar->ppdu_stats_info)) { 148862306a36Sopenharmony_ci list_for_each_entry(ppdu_info, &ar->ppdu_stats_info, list) { 148962306a36Sopenharmony_ci if (ppdu_info->ppdu_id == ppdu_id) 149062306a36Sopenharmony_ci return ppdu_info; 149162306a36Sopenharmony_ci } 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci if (ar->ppdu_stat_list_depth > HTT_PPDU_DESC_MAX_DEPTH) { 149462306a36Sopenharmony_ci ppdu_info = list_first_entry(&ar->ppdu_stats_info, 149562306a36Sopenharmony_ci typeof(*ppdu_info), list); 149662306a36Sopenharmony_ci list_del(&ppdu_info->list); 149762306a36Sopenharmony_ci ar->ppdu_stat_list_depth--; 149862306a36Sopenharmony_ci ath12k_htt_update_ppdu_stats(ar, &ppdu_info->ppdu_stats); 149962306a36Sopenharmony_ci kfree(ppdu_info); 150062306a36Sopenharmony_ci } 150162306a36Sopenharmony_ci } 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci ppdu_info = kzalloc(sizeof(*ppdu_info), GFP_ATOMIC); 150462306a36Sopenharmony_ci if (!ppdu_info) 150562306a36Sopenharmony_ci return NULL; 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci list_add_tail(&ppdu_info->list, &ar->ppdu_stats_info); 150862306a36Sopenharmony_ci ar->ppdu_stat_list_depth++; 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci return ppdu_info; 151162306a36Sopenharmony_ci} 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_cistatic void ath12k_copy_to_delay_stats(struct ath12k_peer *peer, 151462306a36Sopenharmony_ci struct htt_ppdu_user_stats *usr_stats) 151562306a36Sopenharmony_ci{ 151662306a36Sopenharmony_ci peer->ppdu_stats_delayba.sw_peer_id = le16_to_cpu(usr_stats->rate.sw_peer_id); 151762306a36Sopenharmony_ci peer->ppdu_stats_delayba.info0 = le32_to_cpu(usr_stats->rate.info0); 151862306a36Sopenharmony_ci peer->ppdu_stats_delayba.ru_end = le16_to_cpu(usr_stats->rate.ru_end); 151962306a36Sopenharmony_ci peer->ppdu_stats_delayba.ru_start = le16_to_cpu(usr_stats->rate.ru_start); 152062306a36Sopenharmony_ci peer->ppdu_stats_delayba.info1 = le32_to_cpu(usr_stats->rate.info1); 152162306a36Sopenharmony_ci peer->ppdu_stats_delayba.rate_flags = le32_to_cpu(usr_stats->rate.rate_flags); 152262306a36Sopenharmony_ci peer->ppdu_stats_delayba.resp_rate_flags = 152362306a36Sopenharmony_ci le32_to_cpu(usr_stats->rate.resp_rate_flags); 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci peer->delayba_flag = true; 152662306a36Sopenharmony_ci} 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_cistatic void ath12k_copy_to_bar(struct ath12k_peer *peer, 152962306a36Sopenharmony_ci struct htt_ppdu_user_stats *usr_stats) 153062306a36Sopenharmony_ci{ 153162306a36Sopenharmony_ci usr_stats->rate.sw_peer_id = cpu_to_le16(peer->ppdu_stats_delayba.sw_peer_id); 153262306a36Sopenharmony_ci usr_stats->rate.info0 = cpu_to_le32(peer->ppdu_stats_delayba.info0); 153362306a36Sopenharmony_ci usr_stats->rate.ru_end = cpu_to_le16(peer->ppdu_stats_delayba.ru_end); 153462306a36Sopenharmony_ci usr_stats->rate.ru_start = cpu_to_le16(peer->ppdu_stats_delayba.ru_start); 153562306a36Sopenharmony_ci usr_stats->rate.info1 = cpu_to_le32(peer->ppdu_stats_delayba.info1); 153662306a36Sopenharmony_ci usr_stats->rate.rate_flags = cpu_to_le32(peer->ppdu_stats_delayba.rate_flags); 153762306a36Sopenharmony_ci usr_stats->rate.resp_rate_flags = 153862306a36Sopenharmony_ci cpu_to_le32(peer->ppdu_stats_delayba.resp_rate_flags); 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci peer->delayba_flag = false; 154162306a36Sopenharmony_ci} 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_cistatic int ath12k_htt_pull_ppdu_stats(struct ath12k_base *ab, 154462306a36Sopenharmony_ci struct sk_buff *skb) 154562306a36Sopenharmony_ci{ 154662306a36Sopenharmony_ci struct ath12k_htt_ppdu_stats_msg *msg; 154762306a36Sopenharmony_ci struct htt_ppdu_stats_info *ppdu_info; 154862306a36Sopenharmony_ci struct ath12k_peer *peer = NULL; 154962306a36Sopenharmony_ci struct htt_ppdu_user_stats *usr_stats = NULL; 155062306a36Sopenharmony_ci u32 peer_id = 0; 155162306a36Sopenharmony_ci struct ath12k *ar; 155262306a36Sopenharmony_ci int ret, i; 155362306a36Sopenharmony_ci u8 pdev_id; 155462306a36Sopenharmony_ci u32 ppdu_id, len; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci msg = (struct ath12k_htt_ppdu_stats_msg *)skb->data; 155762306a36Sopenharmony_ci len = le32_get_bits(msg->info, HTT_T2H_PPDU_STATS_INFO_PAYLOAD_SIZE); 155862306a36Sopenharmony_ci if (len > (skb->len - struct_size(msg, data, 0))) { 155962306a36Sopenharmony_ci ath12k_warn(ab, 156062306a36Sopenharmony_ci "HTT PPDU STATS event has unexpected payload size %u, should be smaller than %u\n", 156162306a36Sopenharmony_ci len, skb->len); 156262306a36Sopenharmony_ci return -EINVAL; 156362306a36Sopenharmony_ci } 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci pdev_id = le32_get_bits(msg->info, HTT_T2H_PPDU_STATS_INFO_PDEV_ID); 156662306a36Sopenharmony_ci ppdu_id = le32_to_cpu(msg->ppdu_id); 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci rcu_read_lock(); 156962306a36Sopenharmony_ci ar = ath12k_mac_get_ar_by_pdev_id(ab, pdev_id); 157062306a36Sopenharmony_ci if (!ar) { 157162306a36Sopenharmony_ci ret = -EINVAL; 157262306a36Sopenharmony_ci goto exit; 157362306a36Sopenharmony_ci } 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 157662306a36Sopenharmony_ci ppdu_info = ath12k_dp_htt_get_ppdu_desc(ar, ppdu_id); 157762306a36Sopenharmony_ci if (!ppdu_info) { 157862306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 157962306a36Sopenharmony_ci ret = -EINVAL; 158062306a36Sopenharmony_ci goto exit; 158162306a36Sopenharmony_ci } 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci ppdu_info->ppdu_id = ppdu_id; 158462306a36Sopenharmony_ci ret = ath12k_dp_htt_tlv_iter(ab, msg->data, len, 158562306a36Sopenharmony_ci ath12k_htt_tlv_ppdu_stats_parse, 158662306a36Sopenharmony_ci (void *)ppdu_info); 158762306a36Sopenharmony_ci if (ret) { 158862306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 158962306a36Sopenharmony_ci ath12k_warn(ab, "Failed to parse tlv %d\n", ret); 159062306a36Sopenharmony_ci goto exit; 159162306a36Sopenharmony_ci } 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci if (ppdu_info->ppdu_stats.common.num_users >= HTT_PPDU_STATS_MAX_USERS) { 159462306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 159562306a36Sopenharmony_ci ath12k_warn(ab, 159662306a36Sopenharmony_ci "HTT PPDU STATS event has unexpected num_users %u, should be smaller than %u\n", 159762306a36Sopenharmony_ci ppdu_info->ppdu_stats.common.num_users, 159862306a36Sopenharmony_ci HTT_PPDU_STATS_MAX_USERS); 159962306a36Sopenharmony_ci ret = -EINVAL; 160062306a36Sopenharmony_ci goto exit; 160162306a36Sopenharmony_ci } 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci /* back up data rate tlv for all peers */ 160462306a36Sopenharmony_ci if (ppdu_info->frame_type == HTT_STATS_PPDU_FTYPE_DATA && 160562306a36Sopenharmony_ci (ppdu_info->tlv_bitmap & (1 << HTT_PPDU_STATS_TAG_USR_COMMON)) && 160662306a36Sopenharmony_ci ppdu_info->delay_ba) { 160762306a36Sopenharmony_ci for (i = 0; i < ppdu_info->ppdu_stats.common.num_users; i++) { 160862306a36Sopenharmony_ci peer_id = ppdu_info->ppdu_stats.user_stats[i].peer_id; 160962306a36Sopenharmony_ci spin_lock_bh(&ab->base_lock); 161062306a36Sopenharmony_ci peer = ath12k_peer_find_by_id(ab, peer_id); 161162306a36Sopenharmony_ci if (!peer) { 161262306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 161362306a36Sopenharmony_ci continue; 161462306a36Sopenharmony_ci } 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci usr_stats = &ppdu_info->ppdu_stats.user_stats[i]; 161762306a36Sopenharmony_ci if (usr_stats->delay_ba) 161862306a36Sopenharmony_ci ath12k_copy_to_delay_stats(peer, usr_stats); 161962306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 162062306a36Sopenharmony_ci } 162162306a36Sopenharmony_ci } 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci /* restore all peers' data rate tlv to mu-bar tlv */ 162462306a36Sopenharmony_ci if (ppdu_info->frame_type == HTT_STATS_PPDU_FTYPE_BAR && 162562306a36Sopenharmony_ci (ppdu_info->tlv_bitmap & (1 << HTT_PPDU_STATS_TAG_USR_COMMON))) { 162662306a36Sopenharmony_ci for (i = 0; i < ppdu_info->bar_num_users; i++) { 162762306a36Sopenharmony_ci peer_id = ppdu_info->ppdu_stats.user_stats[i].peer_id; 162862306a36Sopenharmony_ci spin_lock_bh(&ab->base_lock); 162962306a36Sopenharmony_ci peer = ath12k_peer_find_by_id(ab, peer_id); 163062306a36Sopenharmony_ci if (!peer) { 163162306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 163262306a36Sopenharmony_ci continue; 163362306a36Sopenharmony_ci } 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci usr_stats = &ppdu_info->ppdu_stats.user_stats[i]; 163662306a36Sopenharmony_ci if (peer->delayba_flag) 163762306a36Sopenharmony_ci ath12k_copy_to_bar(peer, usr_stats); 163862306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 163962306a36Sopenharmony_ci } 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ciexit: 164562306a36Sopenharmony_ci rcu_read_unlock(); 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci return ret; 164862306a36Sopenharmony_ci} 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_cistatic void ath12k_htt_mlo_offset_event_handler(struct ath12k_base *ab, 165162306a36Sopenharmony_ci struct sk_buff *skb) 165262306a36Sopenharmony_ci{ 165362306a36Sopenharmony_ci struct ath12k_htt_mlo_offset_msg *msg; 165462306a36Sopenharmony_ci struct ath12k_pdev *pdev; 165562306a36Sopenharmony_ci struct ath12k *ar; 165662306a36Sopenharmony_ci u8 pdev_id; 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci msg = (struct ath12k_htt_mlo_offset_msg *)skb->data; 165962306a36Sopenharmony_ci pdev_id = u32_get_bits(__le32_to_cpu(msg->info), 166062306a36Sopenharmony_ci HTT_T2H_MLO_OFFSET_INFO_PDEV_ID); 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci rcu_read_lock(); 166362306a36Sopenharmony_ci ar = ath12k_mac_get_ar_by_pdev_id(ab, pdev_id); 166462306a36Sopenharmony_ci if (!ar) { 166562306a36Sopenharmony_ci ath12k_warn(ab, "invalid pdev id %d on htt mlo offset\n", pdev_id); 166662306a36Sopenharmony_ci goto exit; 166762306a36Sopenharmony_ci } 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 167062306a36Sopenharmony_ci pdev = ar->pdev; 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci pdev->timestamp.info = __le32_to_cpu(msg->info); 167362306a36Sopenharmony_ci pdev->timestamp.sync_timestamp_lo_us = __le32_to_cpu(msg->sync_timestamp_lo_us); 167462306a36Sopenharmony_ci pdev->timestamp.sync_timestamp_hi_us = __le32_to_cpu(msg->sync_timestamp_hi_us); 167562306a36Sopenharmony_ci pdev->timestamp.mlo_offset_lo = __le32_to_cpu(msg->mlo_offset_lo); 167662306a36Sopenharmony_ci pdev->timestamp.mlo_offset_hi = __le32_to_cpu(msg->mlo_offset_hi); 167762306a36Sopenharmony_ci pdev->timestamp.mlo_offset_clks = __le32_to_cpu(msg->mlo_offset_clks); 167862306a36Sopenharmony_ci pdev->timestamp.mlo_comp_clks = __le32_to_cpu(msg->mlo_comp_clks); 167962306a36Sopenharmony_ci pdev->timestamp.mlo_comp_timer = __le32_to_cpu(msg->mlo_comp_timer); 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 168262306a36Sopenharmony_ciexit: 168362306a36Sopenharmony_ci rcu_read_unlock(); 168462306a36Sopenharmony_ci} 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_civoid ath12k_dp_htt_htc_t2h_msg_handler(struct ath12k_base *ab, 168762306a36Sopenharmony_ci struct sk_buff *skb) 168862306a36Sopenharmony_ci{ 168962306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 169062306a36Sopenharmony_ci struct htt_resp_msg *resp = (struct htt_resp_msg *)skb->data; 169162306a36Sopenharmony_ci enum htt_t2h_msg_type type; 169262306a36Sopenharmony_ci u16 peer_id; 169362306a36Sopenharmony_ci u8 vdev_id; 169462306a36Sopenharmony_ci u8 mac_addr[ETH_ALEN]; 169562306a36Sopenharmony_ci u16 peer_mac_h16; 169662306a36Sopenharmony_ci u16 ast_hash = 0; 169762306a36Sopenharmony_ci u16 hw_peer_id; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci type = le32_get_bits(resp->version_msg.version, HTT_T2H_MSG_TYPE); 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "dp_htt rx msg type :0x%0x\n", type); 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci switch (type) { 170462306a36Sopenharmony_ci case HTT_T2H_MSG_TYPE_VERSION_CONF: 170562306a36Sopenharmony_ci dp->htt_tgt_ver_major = le32_get_bits(resp->version_msg.version, 170662306a36Sopenharmony_ci HTT_T2H_VERSION_CONF_MAJOR); 170762306a36Sopenharmony_ci dp->htt_tgt_ver_minor = le32_get_bits(resp->version_msg.version, 170862306a36Sopenharmony_ci HTT_T2H_VERSION_CONF_MINOR); 170962306a36Sopenharmony_ci complete(&dp->htt_tgt_version_received); 171062306a36Sopenharmony_ci break; 171162306a36Sopenharmony_ci /* TODO: remove unused peer map versions after testing */ 171262306a36Sopenharmony_ci case HTT_T2H_MSG_TYPE_PEER_MAP: 171362306a36Sopenharmony_ci vdev_id = le32_get_bits(resp->peer_map_ev.info, 171462306a36Sopenharmony_ci HTT_T2H_PEER_MAP_INFO_VDEV_ID); 171562306a36Sopenharmony_ci peer_id = le32_get_bits(resp->peer_map_ev.info, 171662306a36Sopenharmony_ci HTT_T2H_PEER_MAP_INFO_PEER_ID); 171762306a36Sopenharmony_ci peer_mac_h16 = le32_get_bits(resp->peer_map_ev.info1, 171862306a36Sopenharmony_ci HTT_T2H_PEER_MAP_INFO1_MAC_ADDR_H16); 171962306a36Sopenharmony_ci ath12k_dp_get_mac_addr(le32_to_cpu(resp->peer_map_ev.mac_addr_l32), 172062306a36Sopenharmony_ci peer_mac_h16, mac_addr); 172162306a36Sopenharmony_ci ath12k_peer_map_event(ab, vdev_id, peer_id, mac_addr, 0, 0); 172262306a36Sopenharmony_ci break; 172362306a36Sopenharmony_ci case HTT_T2H_MSG_TYPE_PEER_MAP2: 172462306a36Sopenharmony_ci vdev_id = le32_get_bits(resp->peer_map_ev.info, 172562306a36Sopenharmony_ci HTT_T2H_PEER_MAP_INFO_VDEV_ID); 172662306a36Sopenharmony_ci peer_id = le32_get_bits(resp->peer_map_ev.info, 172762306a36Sopenharmony_ci HTT_T2H_PEER_MAP_INFO_PEER_ID); 172862306a36Sopenharmony_ci peer_mac_h16 = le32_get_bits(resp->peer_map_ev.info1, 172962306a36Sopenharmony_ci HTT_T2H_PEER_MAP_INFO1_MAC_ADDR_H16); 173062306a36Sopenharmony_ci ath12k_dp_get_mac_addr(le32_to_cpu(resp->peer_map_ev.mac_addr_l32), 173162306a36Sopenharmony_ci peer_mac_h16, mac_addr); 173262306a36Sopenharmony_ci ast_hash = le32_get_bits(resp->peer_map_ev.info2, 173362306a36Sopenharmony_ci HTT_T2H_PEER_MAP_INFO2_AST_HASH_VAL); 173462306a36Sopenharmony_ci hw_peer_id = le32_get_bits(resp->peer_map_ev.info1, 173562306a36Sopenharmony_ci HTT_T2H_PEER_MAP_INFO1_HW_PEER_ID); 173662306a36Sopenharmony_ci ath12k_peer_map_event(ab, vdev_id, peer_id, mac_addr, ast_hash, 173762306a36Sopenharmony_ci hw_peer_id); 173862306a36Sopenharmony_ci break; 173962306a36Sopenharmony_ci case HTT_T2H_MSG_TYPE_PEER_MAP3: 174062306a36Sopenharmony_ci vdev_id = le32_get_bits(resp->peer_map_ev.info, 174162306a36Sopenharmony_ci HTT_T2H_PEER_MAP_INFO_VDEV_ID); 174262306a36Sopenharmony_ci peer_id = le32_get_bits(resp->peer_map_ev.info, 174362306a36Sopenharmony_ci HTT_T2H_PEER_MAP_INFO_PEER_ID); 174462306a36Sopenharmony_ci peer_mac_h16 = le32_get_bits(resp->peer_map_ev.info1, 174562306a36Sopenharmony_ci HTT_T2H_PEER_MAP_INFO1_MAC_ADDR_H16); 174662306a36Sopenharmony_ci ath12k_dp_get_mac_addr(le32_to_cpu(resp->peer_map_ev.mac_addr_l32), 174762306a36Sopenharmony_ci peer_mac_h16, mac_addr); 174862306a36Sopenharmony_ci ath12k_peer_map_event(ab, vdev_id, peer_id, mac_addr, ast_hash, 174962306a36Sopenharmony_ci peer_id); 175062306a36Sopenharmony_ci break; 175162306a36Sopenharmony_ci case HTT_T2H_MSG_TYPE_PEER_UNMAP: 175262306a36Sopenharmony_ci case HTT_T2H_MSG_TYPE_PEER_UNMAP2: 175362306a36Sopenharmony_ci peer_id = le32_get_bits(resp->peer_unmap_ev.info, 175462306a36Sopenharmony_ci HTT_T2H_PEER_UNMAP_INFO_PEER_ID); 175562306a36Sopenharmony_ci ath12k_peer_unmap_event(ab, peer_id); 175662306a36Sopenharmony_ci break; 175762306a36Sopenharmony_ci case HTT_T2H_MSG_TYPE_PPDU_STATS_IND: 175862306a36Sopenharmony_ci ath12k_htt_pull_ppdu_stats(ab, skb); 175962306a36Sopenharmony_ci break; 176062306a36Sopenharmony_ci case HTT_T2H_MSG_TYPE_EXT_STATS_CONF: 176162306a36Sopenharmony_ci break; 176262306a36Sopenharmony_ci case HTT_T2H_MSG_TYPE_MLO_TIMESTAMP_OFFSET_IND: 176362306a36Sopenharmony_ci ath12k_htt_mlo_offset_event_handler(ab, skb); 176462306a36Sopenharmony_ci break; 176562306a36Sopenharmony_ci default: 176662306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "dp_htt event %d not handled\n", 176762306a36Sopenharmony_ci type); 176862306a36Sopenharmony_ci break; 176962306a36Sopenharmony_ci } 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 177262306a36Sopenharmony_ci} 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_cistatic int ath12k_dp_rx_msdu_coalesce(struct ath12k *ar, 177562306a36Sopenharmony_ci struct sk_buff_head *msdu_list, 177662306a36Sopenharmony_ci struct sk_buff *first, struct sk_buff *last, 177762306a36Sopenharmony_ci u8 l3pad_bytes, int msdu_len) 177862306a36Sopenharmony_ci{ 177962306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 178062306a36Sopenharmony_ci struct sk_buff *skb; 178162306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(first); 178262306a36Sopenharmony_ci int buf_first_hdr_len, buf_first_len; 178362306a36Sopenharmony_ci struct hal_rx_desc *ldesc; 178462306a36Sopenharmony_ci int space_extra, rem_len, buf_len; 178562306a36Sopenharmony_ci u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci /* As the msdu is spread across multiple rx buffers, 178862306a36Sopenharmony_ci * find the offset to the start of msdu for computing 178962306a36Sopenharmony_ci * the length of the msdu in the first buffer. 179062306a36Sopenharmony_ci */ 179162306a36Sopenharmony_ci buf_first_hdr_len = hal_rx_desc_sz + l3pad_bytes; 179262306a36Sopenharmony_ci buf_first_len = DP_RX_BUFFER_SIZE - buf_first_hdr_len; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci if (WARN_ON_ONCE(msdu_len <= buf_first_len)) { 179562306a36Sopenharmony_ci skb_put(first, buf_first_hdr_len + msdu_len); 179662306a36Sopenharmony_ci skb_pull(first, buf_first_hdr_len); 179762306a36Sopenharmony_ci return 0; 179862306a36Sopenharmony_ci } 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci ldesc = (struct hal_rx_desc *)last->data; 180162306a36Sopenharmony_ci rxcb->is_first_msdu = ath12k_dp_rx_h_first_msdu(ab, ldesc); 180262306a36Sopenharmony_ci rxcb->is_last_msdu = ath12k_dp_rx_h_last_msdu(ab, ldesc); 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci /* MSDU spans over multiple buffers because the length of the MSDU 180562306a36Sopenharmony_ci * exceeds DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE. So assume the data 180662306a36Sopenharmony_ci * in the first buf is of length DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE. 180762306a36Sopenharmony_ci */ 180862306a36Sopenharmony_ci skb_put(first, DP_RX_BUFFER_SIZE); 180962306a36Sopenharmony_ci skb_pull(first, buf_first_hdr_len); 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci /* When an MSDU spread over multiple buffers MSDU_END 181262306a36Sopenharmony_ci * tlvs are valid only in the last buffer. Copy those tlvs. 181362306a36Sopenharmony_ci */ 181462306a36Sopenharmony_ci ath12k_dp_rx_desc_end_tlv_copy(ab, rxcb->rx_desc, ldesc); 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci space_extra = msdu_len - (buf_first_len + skb_tailroom(first)); 181762306a36Sopenharmony_ci if (space_extra > 0 && 181862306a36Sopenharmony_ci (pskb_expand_head(first, 0, space_extra, GFP_ATOMIC) < 0)) { 181962306a36Sopenharmony_ci /* Free up all buffers of the MSDU */ 182062306a36Sopenharmony_ci while ((skb = __skb_dequeue(msdu_list)) != NULL) { 182162306a36Sopenharmony_ci rxcb = ATH12K_SKB_RXCB(skb); 182262306a36Sopenharmony_ci if (!rxcb->is_continuation) { 182362306a36Sopenharmony_ci dev_kfree_skb_any(skb); 182462306a36Sopenharmony_ci break; 182562306a36Sopenharmony_ci } 182662306a36Sopenharmony_ci dev_kfree_skb_any(skb); 182762306a36Sopenharmony_ci } 182862306a36Sopenharmony_ci return -ENOMEM; 182962306a36Sopenharmony_ci } 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci rem_len = msdu_len - buf_first_len; 183262306a36Sopenharmony_ci while ((skb = __skb_dequeue(msdu_list)) != NULL && rem_len > 0) { 183362306a36Sopenharmony_ci rxcb = ATH12K_SKB_RXCB(skb); 183462306a36Sopenharmony_ci if (rxcb->is_continuation) 183562306a36Sopenharmony_ci buf_len = DP_RX_BUFFER_SIZE - hal_rx_desc_sz; 183662306a36Sopenharmony_ci else 183762306a36Sopenharmony_ci buf_len = rem_len; 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci if (buf_len > (DP_RX_BUFFER_SIZE - hal_rx_desc_sz)) { 184062306a36Sopenharmony_ci WARN_ON_ONCE(1); 184162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 184262306a36Sopenharmony_ci return -EINVAL; 184362306a36Sopenharmony_ci } 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci skb_put(skb, buf_len + hal_rx_desc_sz); 184662306a36Sopenharmony_ci skb_pull(skb, hal_rx_desc_sz); 184762306a36Sopenharmony_ci skb_copy_from_linear_data(skb, skb_put(first, buf_len), 184862306a36Sopenharmony_ci buf_len); 184962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci rem_len -= buf_len; 185262306a36Sopenharmony_ci if (!rxcb->is_continuation) 185362306a36Sopenharmony_ci break; 185462306a36Sopenharmony_ci } 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci return 0; 185762306a36Sopenharmony_ci} 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_cistatic struct sk_buff *ath12k_dp_rx_get_msdu_last_buf(struct sk_buff_head *msdu_list, 186062306a36Sopenharmony_ci struct sk_buff *first) 186162306a36Sopenharmony_ci{ 186262306a36Sopenharmony_ci struct sk_buff *skb; 186362306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(first); 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci if (!rxcb->is_continuation) 186662306a36Sopenharmony_ci return first; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci skb_queue_walk(msdu_list, skb) { 186962306a36Sopenharmony_ci rxcb = ATH12K_SKB_RXCB(skb); 187062306a36Sopenharmony_ci if (!rxcb->is_continuation) 187162306a36Sopenharmony_ci return skb; 187262306a36Sopenharmony_ci } 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci return NULL; 187562306a36Sopenharmony_ci} 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_cistatic void ath12k_dp_rx_h_csum_offload(struct ath12k *ar, struct sk_buff *msdu) 187862306a36Sopenharmony_ci{ 187962306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); 188062306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 188162306a36Sopenharmony_ci bool ip_csum_fail, l4_csum_fail; 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci ip_csum_fail = ath12k_dp_rx_h_ip_cksum_fail(ab, rxcb->rx_desc); 188462306a36Sopenharmony_ci l4_csum_fail = ath12k_dp_rx_h_l4_cksum_fail(ab, rxcb->rx_desc); 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci msdu->ip_summed = (ip_csum_fail || l4_csum_fail) ? 188762306a36Sopenharmony_ci CHECKSUM_NONE : CHECKSUM_UNNECESSARY; 188862306a36Sopenharmony_ci} 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_cistatic int ath12k_dp_rx_crypto_mic_len(struct ath12k *ar, 189162306a36Sopenharmony_ci enum hal_encrypt_type enctype) 189262306a36Sopenharmony_ci{ 189362306a36Sopenharmony_ci switch (enctype) { 189462306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_OPEN: 189562306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_TKIP_NO_MIC: 189662306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_TKIP_MIC: 189762306a36Sopenharmony_ci return 0; 189862306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_CCMP_128: 189962306a36Sopenharmony_ci return IEEE80211_CCMP_MIC_LEN; 190062306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_CCMP_256: 190162306a36Sopenharmony_ci return IEEE80211_CCMP_256_MIC_LEN; 190262306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_GCMP_128: 190362306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_AES_GCMP_256: 190462306a36Sopenharmony_ci return IEEE80211_GCMP_MIC_LEN; 190562306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_WEP_40: 190662306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_WEP_104: 190762306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_WEP_128: 190862306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4: 190962306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_WAPI: 191062306a36Sopenharmony_ci break; 191162306a36Sopenharmony_ci } 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci ath12k_warn(ar->ab, "unsupported encryption type %d for mic len\n", enctype); 191462306a36Sopenharmony_ci return 0; 191562306a36Sopenharmony_ci} 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_cistatic int ath12k_dp_rx_crypto_param_len(struct ath12k *ar, 191862306a36Sopenharmony_ci enum hal_encrypt_type enctype) 191962306a36Sopenharmony_ci{ 192062306a36Sopenharmony_ci switch (enctype) { 192162306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_OPEN: 192262306a36Sopenharmony_ci return 0; 192362306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_TKIP_NO_MIC: 192462306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_TKIP_MIC: 192562306a36Sopenharmony_ci return IEEE80211_TKIP_IV_LEN; 192662306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_CCMP_128: 192762306a36Sopenharmony_ci return IEEE80211_CCMP_HDR_LEN; 192862306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_CCMP_256: 192962306a36Sopenharmony_ci return IEEE80211_CCMP_256_HDR_LEN; 193062306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_GCMP_128: 193162306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_AES_GCMP_256: 193262306a36Sopenharmony_ci return IEEE80211_GCMP_HDR_LEN; 193362306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_WEP_40: 193462306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_WEP_104: 193562306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_WEP_128: 193662306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4: 193762306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_WAPI: 193862306a36Sopenharmony_ci break; 193962306a36Sopenharmony_ci } 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci ath12k_warn(ar->ab, "unsupported encryption type %d\n", enctype); 194262306a36Sopenharmony_ci return 0; 194362306a36Sopenharmony_ci} 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_cistatic int ath12k_dp_rx_crypto_icv_len(struct ath12k *ar, 194662306a36Sopenharmony_ci enum hal_encrypt_type enctype) 194762306a36Sopenharmony_ci{ 194862306a36Sopenharmony_ci switch (enctype) { 194962306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_OPEN: 195062306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_CCMP_128: 195162306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_CCMP_256: 195262306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_GCMP_128: 195362306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_AES_GCMP_256: 195462306a36Sopenharmony_ci return 0; 195562306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_TKIP_NO_MIC: 195662306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_TKIP_MIC: 195762306a36Sopenharmony_ci return IEEE80211_TKIP_ICV_LEN; 195862306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_WEP_40: 195962306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_WEP_104: 196062306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_WEP_128: 196162306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4: 196262306a36Sopenharmony_ci case HAL_ENCRYPT_TYPE_WAPI: 196362306a36Sopenharmony_ci break; 196462306a36Sopenharmony_ci } 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci ath12k_warn(ar->ab, "unsupported encryption type %d\n", enctype); 196762306a36Sopenharmony_ci return 0; 196862306a36Sopenharmony_ci} 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_cistatic void ath12k_dp_rx_h_undecap_nwifi(struct ath12k *ar, 197162306a36Sopenharmony_ci struct sk_buff *msdu, 197262306a36Sopenharmony_ci enum hal_encrypt_type enctype, 197362306a36Sopenharmony_ci struct ieee80211_rx_status *status) 197462306a36Sopenharmony_ci{ 197562306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 197662306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); 197762306a36Sopenharmony_ci u8 decap_hdr[DP_MAX_NWIFI_HDR_LEN]; 197862306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 197962306a36Sopenharmony_ci size_t hdr_len; 198062306a36Sopenharmony_ci u8 *crypto_hdr; 198162306a36Sopenharmony_ci u16 qos_ctl; 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci /* pull decapped header */ 198462306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)msdu->data; 198562306a36Sopenharmony_ci hdr_len = ieee80211_hdrlen(hdr->frame_control); 198662306a36Sopenharmony_ci skb_pull(msdu, hdr_len); 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci /* Rebuild qos header */ 198962306a36Sopenharmony_ci hdr->frame_control |= __cpu_to_le16(IEEE80211_STYPE_QOS_DATA); 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci /* Reset the order bit as the HT_Control header is stripped */ 199262306a36Sopenharmony_ci hdr->frame_control &= ~(__cpu_to_le16(IEEE80211_FCTL_ORDER)); 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci qos_ctl = rxcb->tid; 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci if (ath12k_dp_rx_h_mesh_ctl_present(ab, rxcb->rx_desc)) 199762306a36Sopenharmony_ci qos_ctl |= IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT; 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci /* TODO: Add other QoS ctl fields when required */ 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci /* copy decap header before overwriting for reuse below */ 200262306a36Sopenharmony_ci memcpy(decap_hdr, hdr, hdr_len); 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci /* Rebuild crypto header for mac80211 use */ 200562306a36Sopenharmony_ci if (!(status->flag & RX_FLAG_IV_STRIPPED)) { 200662306a36Sopenharmony_ci crypto_hdr = skb_push(msdu, ath12k_dp_rx_crypto_param_len(ar, enctype)); 200762306a36Sopenharmony_ci ath12k_dp_rx_desc_get_crypto_header(ar->ab, 200862306a36Sopenharmony_ci rxcb->rx_desc, crypto_hdr, 200962306a36Sopenharmony_ci enctype); 201062306a36Sopenharmony_ci } 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci memcpy(skb_push(msdu, 201362306a36Sopenharmony_ci IEEE80211_QOS_CTL_LEN), &qos_ctl, 201462306a36Sopenharmony_ci IEEE80211_QOS_CTL_LEN); 201562306a36Sopenharmony_ci memcpy(skb_push(msdu, hdr_len), decap_hdr, hdr_len); 201662306a36Sopenharmony_ci} 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_cistatic void ath12k_dp_rx_h_undecap_raw(struct ath12k *ar, struct sk_buff *msdu, 201962306a36Sopenharmony_ci enum hal_encrypt_type enctype, 202062306a36Sopenharmony_ci struct ieee80211_rx_status *status, 202162306a36Sopenharmony_ci bool decrypted) 202262306a36Sopenharmony_ci{ 202362306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); 202462306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 202562306a36Sopenharmony_ci size_t hdr_len; 202662306a36Sopenharmony_ci size_t crypto_len; 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci if (!rxcb->is_first_msdu || 202962306a36Sopenharmony_ci !(rxcb->is_first_msdu && rxcb->is_last_msdu)) { 203062306a36Sopenharmony_ci WARN_ON_ONCE(1); 203162306a36Sopenharmony_ci return; 203262306a36Sopenharmony_ci } 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci skb_trim(msdu, msdu->len - FCS_LEN); 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci if (!decrypted) 203762306a36Sopenharmony_ci return; 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci hdr = (void *)msdu->data; 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_ci /* Tail */ 204262306a36Sopenharmony_ci if (status->flag & RX_FLAG_IV_STRIPPED) { 204362306a36Sopenharmony_ci skb_trim(msdu, msdu->len - 204462306a36Sopenharmony_ci ath12k_dp_rx_crypto_mic_len(ar, enctype)); 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci skb_trim(msdu, msdu->len - 204762306a36Sopenharmony_ci ath12k_dp_rx_crypto_icv_len(ar, enctype)); 204862306a36Sopenharmony_ci } else { 204962306a36Sopenharmony_ci /* MIC */ 205062306a36Sopenharmony_ci if (status->flag & RX_FLAG_MIC_STRIPPED) 205162306a36Sopenharmony_ci skb_trim(msdu, msdu->len - 205262306a36Sopenharmony_ci ath12k_dp_rx_crypto_mic_len(ar, enctype)); 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci /* ICV */ 205562306a36Sopenharmony_ci if (status->flag & RX_FLAG_ICV_STRIPPED) 205662306a36Sopenharmony_ci skb_trim(msdu, msdu->len - 205762306a36Sopenharmony_ci ath12k_dp_rx_crypto_icv_len(ar, enctype)); 205862306a36Sopenharmony_ci } 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ci /* MMIC */ 206162306a36Sopenharmony_ci if ((status->flag & RX_FLAG_MMIC_STRIPPED) && 206262306a36Sopenharmony_ci !ieee80211_has_morefrags(hdr->frame_control) && 206362306a36Sopenharmony_ci enctype == HAL_ENCRYPT_TYPE_TKIP_MIC) 206462306a36Sopenharmony_ci skb_trim(msdu, msdu->len - IEEE80211_CCMP_MIC_LEN); 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci /* Head */ 206762306a36Sopenharmony_ci if (status->flag & RX_FLAG_IV_STRIPPED) { 206862306a36Sopenharmony_ci hdr_len = ieee80211_hdrlen(hdr->frame_control); 206962306a36Sopenharmony_ci crypto_len = ath12k_dp_rx_crypto_param_len(ar, enctype); 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci memmove(msdu->data + crypto_len, msdu->data, hdr_len); 207262306a36Sopenharmony_ci skb_pull(msdu, crypto_len); 207362306a36Sopenharmony_ci } 207462306a36Sopenharmony_ci} 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_cistatic void ath12k_get_dot11_hdr_from_rx_desc(struct ath12k *ar, 207762306a36Sopenharmony_ci struct sk_buff *msdu, 207862306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb, 207962306a36Sopenharmony_ci struct ieee80211_rx_status *status, 208062306a36Sopenharmony_ci enum hal_encrypt_type enctype) 208162306a36Sopenharmony_ci{ 208262306a36Sopenharmony_ci struct hal_rx_desc *rx_desc = rxcb->rx_desc; 208362306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 208462306a36Sopenharmony_ci size_t hdr_len, crypto_len; 208562306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 208662306a36Sopenharmony_ci u16 qos_ctl; 208762306a36Sopenharmony_ci __le16 fc; 208862306a36Sopenharmony_ci u8 *crypto_hdr; 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci if (!(status->flag & RX_FLAG_IV_STRIPPED)) { 209162306a36Sopenharmony_ci crypto_len = ath12k_dp_rx_crypto_param_len(ar, enctype); 209262306a36Sopenharmony_ci crypto_hdr = skb_push(msdu, crypto_len); 209362306a36Sopenharmony_ci ath12k_dp_rx_desc_get_crypto_header(ab, rx_desc, crypto_hdr, enctype); 209462306a36Sopenharmony_ci } 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci fc = cpu_to_le16(ath12k_dp_rxdesc_get_mpdu_frame_ctrl(ab, rx_desc)); 209762306a36Sopenharmony_ci hdr_len = ieee80211_hdrlen(fc); 209862306a36Sopenharmony_ci skb_push(msdu, hdr_len); 209962306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)msdu->data; 210062306a36Sopenharmony_ci hdr->frame_control = fc; 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci /* Get wifi header from rx_desc */ 210362306a36Sopenharmony_ci ath12k_dp_rx_desc_get_dot11_hdr(ab, rx_desc, hdr); 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci if (rxcb->is_mcbc) 210662306a36Sopenharmony_ci status->flag &= ~RX_FLAG_PN_VALIDATED; 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci /* Add QOS header */ 210962306a36Sopenharmony_ci if (ieee80211_is_data_qos(hdr->frame_control)) { 211062306a36Sopenharmony_ci qos_ctl = rxcb->tid; 211162306a36Sopenharmony_ci if (ath12k_dp_rx_h_mesh_ctl_present(ab, rx_desc)) 211262306a36Sopenharmony_ci qos_ctl |= IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT; 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci /* TODO: Add other QoS ctl fields when required */ 211562306a36Sopenharmony_ci memcpy(msdu->data + (hdr_len - IEEE80211_QOS_CTL_LEN), 211662306a36Sopenharmony_ci &qos_ctl, IEEE80211_QOS_CTL_LEN); 211762306a36Sopenharmony_ci } 211862306a36Sopenharmony_ci} 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_cistatic void ath12k_dp_rx_h_undecap_eth(struct ath12k *ar, 212162306a36Sopenharmony_ci struct sk_buff *msdu, 212262306a36Sopenharmony_ci enum hal_encrypt_type enctype, 212362306a36Sopenharmony_ci struct ieee80211_rx_status *status) 212462306a36Sopenharmony_ci{ 212562306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 212662306a36Sopenharmony_ci struct ethhdr *eth; 212762306a36Sopenharmony_ci u8 da[ETH_ALEN]; 212862306a36Sopenharmony_ci u8 sa[ETH_ALEN]; 212962306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); 213062306a36Sopenharmony_ci struct ath12k_dp_rx_rfc1042_hdr rfc = {0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}}; 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci eth = (struct ethhdr *)msdu->data; 213362306a36Sopenharmony_ci ether_addr_copy(da, eth->h_dest); 213462306a36Sopenharmony_ci ether_addr_copy(sa, eth->h_source); 213562306a36Sopenharmony_ci rfc.snap_type = eth->h_proto; 213662306a36Sopenharmony_ci skb_pull(msdu, sizeof(*eth)); 213762306a36Sopenharmony_ci memcpy(skb_push(msdu, sizeof(rfc)), &rfc, 213862306a36Sopenharmony_ci sizeof(rfc)); 213962306a36Sopenharmony_ci ath12k_get_dot11_hdr_from_rx_desc(ar, msdu, rxcb, status, enctype); 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci /* original 802.11 header has a different DA and in 214262306a36Sopenharmony_ci * case of 4addr it may also have different SA 214362306a36Sopenharmony_ci */ 214462306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)msdu->data; 214562306a36Sopenharmony_ci ether_addr_copy(ieee80211_get_DA(hdr), da); 214662306a36Sopenharmony_ci ether_addr_copy(ieee80211_get_SA(hdr), sa); 214762306a36Sopenharmony_ci} 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_cistatic void ath12k_dp_rx_h_undecap(struct ath12k *ar, struct sk_buff *msdu, 215062306a36Sopenharmony_ci struct hal_rx_desc *rx_desc, 215162306a36Sopenharmony_ci enum hal_encrypt_type enctype, 215262306a36Sopenharmony_ci struct ieee80211_rx_status *status, 215362306a36Sopenharmony_ci bool decrypted) 215462306a36Sopenharmony_ci{ 215562306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 215662306a36Sopenharmony_ci u8 decap; 215762306a36Sopenharmony_ci struct ethhdr *ehdr; 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci decap = ath12k_dp_rx_h_decap_type(ab, rx_desc); 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci switch (decap) { 216262306a36Sopenharmony_ci case DP_RX_DECAP_TYPE_NATIVE_WIFI: 216362306a36Sopenharmony_ci ath12k_dp_rx_h_undecap_nwifi(ar, msdu, enctype, status); 216462306a36Sopenharmony_ci break; 216562306a36Sopenharmony_ci case DP_RX_DECAP_TYPE_RAW: 216662306a36Sopenharmony_ci ath12k_dp_rx_h_undecap_raw(ar, msdu, enctype, status, 216762306a36Sopenharmony_ci decrypted); 216862306a36Sopenharmony_ci break; 216962306a36Sopenharmony_ci case DP_RX_DECAP_TYPE_ETHERNET2_DIX: 217062306a36Sopenharmony_ci ehdr = (struct ethhdr *)msdu->data; 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci /* mac80211 allows fast path only for authorized STA */ 217362306a36Sopenharmony_ci if (ehdr->h_proto == cpu_to_be16(ETH_P_PAE)) { 217462306a36Sopenharmony_ci ATH12K_SKB_RXCB(msdu)->is_eapol = true; 217562306a36Sopenharmony_ci ath12k_dp_rx_h_undecap_eth(ar, msdu, enctype, status); 217662306a36Sopenharmony_ci break; 217762306a36Sopenharmony_ci } 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_ci /* PN for mcast packets will be validated in mac80211; 218062306a36Sopenharmony_ci * remove eth header and add 802.11 header. 218162306a36Sopenharmony_ci */ 218262306a36Sopenharmony_ci if (ATH12K_SKB_RXCB(msdu)->is_mcbc && decrypted) 218362306a36Sopenharmony_ci ath12k_dp_rx_h_undecap_eth(ar, msdu, enctype, status); 218462306a36Sopenharmony_ci break; 218562306a36Sopenharmony_ci case DP_RX_DECAP_TYPE_8023: 218662306a36Sopenharmony_ci /* TODO: Handle undecap for these formats */ 218762306a36Sopenharmony_ci break; 218862306a36Sopenharmony_ci } 218962306a36Sopenharmony_ci} 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_cistruct ath12k_peer * 219262306a36Sopenharmony_ciath12k_dp_rx_h_find_peer(struct ath12k_base *ab, struct sk_buff *msdu) 219362306a36Sopenharmony_ci{ 219462306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); 219562306a36Sopenharmony_ci struct hal_rx_desc *rx_desc = rxcb->rx_desc; 219662306a36Sopenharmony_ci struct ath12k_peer *peer = NULL; 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci lockdep_assert_held(&ab->base_lock); 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci if (rxcb->peer_id) 220162306a36Sopenharmony_ci peer = ath12k_peer_find_by_id(ab, rxcb->peer_id); 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci if (peer) 220462306a36Sopenharmony_ci return peer; 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci if (!rx_desc || !(ath12k_dp_rxdesc_mac_addr2_valid(ab, rx_desc))) 220762306a36Sopenharmony_ci return NULL; 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci peer = ath12k_peer_find_by_addr(ab, 221062306a36Sopenharmony_ci ath12k_dp_rxdesc_get_mpdu_start_addr2(ab, 221162306a36Sopenharmony_ci rx_desc)); 221262306a36Sopenharmony_ci return peer; 221362306a36Sopenharmony_ci} 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_cistatic void ath12k_dp_rx_h_mpdu(struct ath12k *ar, 221662306a36Sopenharmony_ci struct sk_buff *msdu, 221762306a36Sopenharmony_ci struct hal_rx_desc *rx_desc, 221862306a36Sopenharmony_ci struct ieee80211_rx_status *rx_status) 221962306a36Sopenharmony_ci{ 222062306a36Sopenharmony_ci bool fill_crypto_hdr; 222162306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 222262306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb; 222362306a36Sopenharmony_ci enum hal_encrypt_type enctype; 222462306a36Sopenharmony_ci bool is_decrypted = false; 222562306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 222662306a36Sopenharmony_ci struct ath12k_peer *peer; 222762306a36Sopenharmony_ci u32 err_bitmap; 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci /* PN for multicast packets will be checked in mac80211 */ 223062306a36Sopenharmony_ci rxcb = ATH12K_SKB_RXCB(msdu); 223162306a36Sopenharmony_ci fill_crypto_hdr = ath12k_dp_rx_h_is_da_mcbc(ar->ab, rx_desc); 223262306a36Sopenharmony_ci rxcb->is_mcbc = fill_crypto_hdr; 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci if (rxcb->is_mcbc) 223562306a36Sopenharmony_ci rxcb->peer_id = ath12k_dp_rx_h_peer_id(ar->ab, rx_desc); 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci spin_lock_bh(&ar->ab->base_lock); 223862306a36Sopenharmony_ci peer = ath12k_dp_rx_h_find_peer(ar->ab, msdu); 223962306a36Sopenharmony_ci if (peer) { 224062306a36Sopenharmony_ci if (rxcb->is_mcbc) 224162306a36Sopenharmony_ci enctype = peer->sec_type_grp; 224262306a36Sopenharmony_ci else 224362306a36Sopenharmony_ci enctype = peer->sec_type; 224462306a36Sopenharmony_ci } else { 224562306a36Sopenharmony_ci enctype = HAL_ENCRYPT_TYPE_OPEN; 224662306a36Sopenharmony_ci } 224762306a36Sopenharmony_ci spin_unlock_bh(&ar->ab->base_lock); 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci err_bitmap = ath12k_dp_rx_h_mpdu_err(ab, rx_desc); 225062306a36Sopenharmony_ci if (enctype != HAL_ENCRYPT_TYPE_OPEN && !err_bitmap) 225162306a36Sopenharmony_ci is_decrypted = ath12k_dp_rx_h_is_decrypted(ab, rx_desc); 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_ci /* Clear per-MPDU flags while leaving per-PPDU flags intact */ 225462306a36Sopenharmony_ci rx_status->flag &= ~(RX_FLAG_FAILED_FCS_CRC | 225562306a36Sopenharmony_ci RX_FLAG_MMIC_ERROR | 225662306a36Sopenharmony_ci RX_FLAG_DECRYPTED | 225762306a36Sopenharmony_ci RX_FLAG_IV_STRIPPED | 225862306a36Sopenharmony_ci RX_FLAG_MMIC_STRIPPED); 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci if (err_bitmap & HAL_RX_MPDU_ERR_FCS) 226162306a36Sopenharmony_ci rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; 226262306a36Sopenharmony_ci if (err_bitmap & HAL_RX_MPDU_ERR_TKIP_MIC) 226362306a36Sopenharmony_ci rx_status->flag |= RX_FLAG_MMIC_ERROR; 226462306a36Sopenharmony_ci 226562306a36Sopenharmony_ci if (is_decrypted) { 226662306a36Sopenharmony_ci rx_status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_MMIC_STRIPPED; 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci if (fill_crypto_hdr) 226962306a36Sopenharmony_ci rx_status->flag |= RX_FLAG_MIC_STRIPPED | 227062306a36Sopenharmony_ci RX_FLAG_ICV_STRIPPED; 227162306a36Sopenharmony_ci else 227262306a36Sopenharmony_ci rx_status->flag |= RX_FLAG_IV_STRIPPED | 227362306a36Sopenharmony_ci RX_FLAG_PN_VALIDATED; 227462306a36Sopenharmony_ci } 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci ath12k_dp_rx_h_csum_offload(ar, msdu); 227762306a36Sopenharmony_ci ath12k_dp_rx_h_undecap(ar, msdu, rx_desc, 227862306a36Sopenharmony_ci enctype, rx_status, is_decrypted); 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_ci if (!is_decrypted || fill_crypto_hdr) 228162306a36Sopenharmony_ci return; 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci if (ath12k_dp_rx_h_decap_type(ar->ab, rx_desc) != 228462306a36Sopenharmony_ci DP_RX_DECAP_TYPE_ETHERNET2_DIX) { 228562306a36Sopenharmony_ci hdr = (void *)msdu->data; 228662306a36Sopenharmony_ci hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); 228762306a36Sopenharmony_ci } 228862306a36Sopenharmony_ci} 228962306a36Sopenharmony_ci 229062306a36Sopenharmony_cistatic void ath12k_dp_rx_h_rate(struct ath12k *ar, struct hal_rx_desc *rx_desc, 229162306a36Sopenharmony_ci struct ieee80211_rx_status *rx_status) 229262306a36Sopenharmony_ci{ 229362306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 229462306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 229562306a36Sopenharmony_ci enum rx_msdu_start_pkt_type pkt_type; 229662306a36Sopenharmony_ci u8 bw; 229762306a36Sopenharmony_ci u8 rate_mcs, nss; 229862306a36Sopenharmony_ci u8 sgi; 229962306a36Sopenharmony_ci bool is_cck; 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci pkt_type = ath12k_dp_rx_h_pkt_type(ab, rx_desc); 230262306a36Sopenharmony_ci bw = ath12k_dp_rx_h_rx_bw(ab, rx_desc); 230362306a36Sopenharmony_ci rate_mcs = ath12k_dp_rx_h_rate_mcs(ab, rx_desc); 230462306a36Sopenharmony_ci nss = ath12k_dp_rx_h_nss(ab, rx_desc); 230562306a36Sopenharmony_ci sgi = ath12k_dp_rx_h_sgi(ab, rx_desc); 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci switch (pkt_type) { 230862306a36Sopenharmony_ci case RX_MSDU_START_PKT_TYPE_11A: 230962306a36Sopenharmony_ci case RX_MSDU_START_PKT_TYPE_11B: 231062306a36Sopenharmony_ci is_cck = (pkt_type == RX_MSDU_START_PKT_TYPE_11B); 231162306a36Sopenharmony_ci sband = &ar->mac.sbands[rx_status->band]; 231262306a36Sopenharmony_ci rx_status->rate_idx = ath12k_mac_hw_rate_to_idx(sband, rate_mcs, 231362306a36Sopenharmony_ci is_cck); 231462306a36Sopenharmony_ci break; 231562306a36Sopenharmony_ci case RX_MSDU_START_PKT_TYPE_11N: 231662306a36Sopenharmony_ci rx_status->encoding = RX_ENC_HT; 231762306a36Sopenharmony_ci if (rate_mcs > ATH12K_HT_MCS_MAX) { 231862306a36Sopenharmony_ci ath12k_warn(ar->ab, 231962306a36Sopenharmony_ci "Received with invalid mcs in HT mode %d\n", 232062306a36Sopenharmony_ci rate_mcs); 232162306a36Sopenharmony_ci break; 232262306a36Sopenharmony_ci } 232362306a36Sopenharmony_ci rx_status->rate_idx = rate_mcs + (8 * (nss - 1)); 232462306a36Sopenharmony_ci if (sgi) 232562306a36Sopenharmony_ci rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; 232662306a36Sopenharmony_ci rx_status->bw = ath12k_mac_bw_to_mac80211_bw(bw); 232762306a36Sopenharmony_ci break; 232862306a36Sopenharmony_ci case RX_MSDU_START_PKT_TYPE_11AC: 232962306a36Sopenharmony_ci rx_status->encoding = RX_ENC_VHT; 233062306a36Sopenharmony_ci rx_status->rate_idx = rate_mcs; 233162306a36Sopenharmony_ci if (rate_mcs > ATH12K_VHT_MCS_MAX) { 233262306a36Sopenharmony_ci ath12k_warn(ar->ab, 233362306a36Sopenharmony_ci "Received with invalid mcs in VHT mode %d\n", 233462306a36Sopenharmony_ci rate_mcs); 233562306a36Sopenharmony_ci break; 233662306a36Sopenharmony_ci } 233762306a36Sopenharmony_ci rx_status->nss = nss; 233862306a36Sopenharmony_ci if (sgi) 233962306a36Sopenharmony_ci rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; 234062306a36Sopenharmony_ci rx_status->bw = ath12k_mac_bw_to_mac80211_bw(bw); 234162306a36Sopenharmony_ci break; 234262306a36Sopenharmony_ci case RX_MSDU_START_PKT_TYPE_11AX: 234362306a36Sopenharmony_ci rx_status->rate_idx = rate_mcs; 234462306a36Sopenharmony_ci if (rate_mcs > ATH12K_HE_MCS_MAX) { 234562306a36Sopenharmony_ci ath12k_warn(ar->ab, 234662306a36Sopenharmony_ci "Received with invalid mcs in HE mode %d\n", 234762306a36Sopenharmony_ci rate_mcs); 234862306a36Sopenharmony_ci break; 234962306a36Sopenharmony_ci } 235062306a36Sopenharmony_ci rx_status->encoding = RX_ENC_HE; 235162306a36Sopenharmony_ci rx_status->nss = nss; 235262306a36Sopenharmony_ci rx_status->he_gi = ath12k_he_gi_to_nl80211_he_gi(sgi); 235362306a36Sopenharmony_ci rx_status->bw = ath12k_mac_bw_to_mac80211_bw(bw); 235462306a36Sopenharmony_ci break; 235562306a36Sopenharmony_ci } 235662306a36Sopenharmony_ci} 235762306a36Sopenharmony_ci 235862306a36Sopenharmony_civoid ath12k_dp_rx_h_ppdu(struct ath12k *ar, struct hal_rx_desc *rx_desc, 235962306a36Sopenharmony_ci struct ieee80211_rx_status *rx_status) 236062306a36Sopenharmony_ci{ 236162306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 236262306a36Sopenharmony_ci u8 channel_num; 236362306a36Sopenharmony_ci u32 center_freq, meta_data; 236462306a36Sopenharmony_ci struct ieee80211_channel *channel; 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci rx_status->freq = 0; 236762306a36Sopenharmony_ci rx_status->rate_idx = 0; 236862306a36Sopenharmony_ci rx_status->nss = 0; 236962306a36Sopenharmony_ci rx_status->encoding = RX_ENC_LEGACY; 237062306a36Sopenharmony_ci rx_status->bw = RATE_INFO_BW_20; 237162306a36Sopenharmony_ci rx_status->enc_flags = 0; 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci meta_data = ath12k_dp_rx_h_freq(ab, rx_desc); 237662306a36Sopenharmony_ci channel_num = meta_data; 237762306a36Sopenharmony_ci center_freq = meta_data >> 16; 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_ci if (center_freq >= 5935 && center_freq <= 7105) { 238062306a36Sopenharmony_ci rx_status->band = NL80211_BAND_6GHZ; 238162306a36Sopenharmony_ci } else if (channel_num >= 1 && channel_num <= 14) { 238262306a36Sopenharmony_ci rx_status->band = NL80211_BAND_2GHZ; 238362306a36Sopenharmony_ci } else if (channel_num >= 36 && channel_num <= 173) { 238462306a36Sopenharmony_ci rx_status->band = NL80211_BAND_5GHZ; 238562306a36Sopenharmony_ci } else { 238662306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 238762306a36Sopenharmony_ci channel = ar->rx_channel; 238862306a36Sopenharmony_ci if (channel) { 238962306a36Sopenharmony_ci rx_status->band = channel->band; 239062306a36Sopenharmony_ci channel_num = 239162306a36Sopenharmony_ci ieee80211_frequency_to_channel(channel->center_freq); 239262306a36Sopenharmony_ci } 239362306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 239462306a36Sopenharmony_ci ath12k_dbg_dump(ar->ab, ATH12K_DBG_DATA, NULL, "rx_desc: ", 239562306a36Sopenharmony_ci rx_desc, sizeof(*rx_desc)); 239662306a36Sopenharmony_ci } 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci rx_status->freq = ieee80211_channel_to_frequency(channel_num, 239962306a36Sopenharmony_ci rx_status->band); 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_ci ath12k_dp_rx_h_rate(ar, rx_desc, rx_status); 240262306a36Sopenharmony_ci} 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_cistatic void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *napi, 240562306a36Sopenharmony_ci struct sk_buff *msdu, 240662306a36Sopenharmony_ci struct ieee80211_rx_status *status) 240762306a36Sopenharmony_ci{ 240862306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 240962306a36Sopenharmony_ci static const struct ieee80211_radiotap_he known = { 241062306a36Sopenharmony_ci .data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | 241162306a36Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN), 241262306a36Sopenharmony_ci .data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN), 241362306a36Sopenharmony_ci }; 241462306a36Sopenharmony_ci struct ieee80211_radiotap_he *he; 241562306a36Sopenharmony_ci struct ieee80211_rx_status *rx_status; 241662306a36Sopenharmony_ci struct ieee80211_sta *pubsta; 241762306a36Sopenharmony_ci struct ath12k_peer *peer; 241862306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); 241962306a36Sopenharmony_ci u8 decap = DP_RX_DECAP_TYPE_RAW; 242062306a36Sopenharmony_ci bool is_mcbc = rxcb->is_mcbc; 242162306a36Sopenharmony_ci bool is_eapol = rxcb->is_eapol; 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_ci if (status->encoding == RX_ENC_HE && !(status->flag & RX_FLAG_RADIOTAP_HE) && 242462306a36Sopenharmony_ci !(status->flag & RX_FLAG_SKIP_MONITOR)) { 242562306a36Sopenharmony_ci he = skb_push(msdu, sizeof(known)); 242662306a36Sopenharmony_ci memcpy(he, &known, sizeof(known)); 242762306a36Sopenharmony_ci status->flag |= RX_FLAG_RADIOTAP_HE; 242862306a36Sopenharmony_ci } 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_ci if (!(status->flag & RX_FLAG_ONLY_MONITOR)) 243162306a36Sopenharmony_ci decap = ath12k_dp_rx_h_decap_type(ab, rxcb->rx_desc); 243262306a36Sopenharmony_ci 243362306a36Sopenharmony_ci spin_lock_bh(&ab->base_lock); 243462306a36Sopenharmony_ci peer = ath12k_dp_rx_h_find_peer(ab, msdu); 243562306a36Sopenharmony_ci 243662306a36Sopenharmony_ci pubsta = peer ? peer->sta : NULL; 243762306a36Sopenharmony_ci 243862306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_DATA, 244162306a36Sopenharmony_ci "rx skb %pK len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", 244262306a36Sopenharmony_ci msdu, 244362306a36Sopenharmony_ci msdu->len, 244462306a36Sopenharmony_ci peer ? peer->addr : NULL, 244562306a36Sopenharmony_ci rxcb->tid, 244662306a36Sopenharmony_ci is_mcbc ? "mcast" : "ucast", 244762306a36Sopenharmony_ci ath12k_dp_rx_h_seq_no(ab, rxcb->rx_desc), 244862306a36Sopenharmony_ci (status->encoding == RX_ENC_LEGACY) ? "legacy" : "", 244962306a36Sopenharmony_ci (status->encoding == RX_ENC_HT) ? "ht" : "", 245062306a36Sopenharmony_ci (status->encoding == RX_ENC_VHT) ? "vht" : "", 245162306a36Sopenharmony_ci (status->encoding == RX_ENC_HE) ? "he" : "", 245262306a36Sopenharmony_ci (status->bw == RATE_INFO_BW_40) ? "40" : "", 245362306a36Sopenharmony_ci (status->bw == RATE_INFO_BW_80) ? "80" : "", 245462306a36Sopenharmony_ci (status->bw == RATE_INFO_BW_160) ? "160" : "", 245562306a36Sopenharmony_ci status->enc_flags & RX_ENC_FLAG_SHORT_GI ? "sgi " : "", 245662306a36Sopenharmony_ci status->rate_idx, 245762306a36Sopenharmony_ci status->nss, 245862306a36Sopenharmony_ci status->freq, 245962306a36Sopenharmony_ci status->band, status->flag, 246062306a36Sopenharmony_ci !!(status->flag & RX_FLAG_FAILED_FCS_CRC), 246162306a36Sopenharmony_ci !!(status->flag & RX_FLAG_MMIC_ERROR), 246262306a36Sopenharmony_ci !!(status->flag & RX_FLAG_AMSDU_MORE)); 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci ath12k_dbg_dump(ab, ATH12K_DBG_DP_RX, NULL, "dp rx msdu: ", 246562306a36Sopenharmony_ci msdu->data, msdu->len); 246662306a36Sopenharmony_ci 246762306a36Sopenharmony_ci rx_status = IEEE80211_SKB_RXCB(msdu); 246862306a36Sopenharmony_ci *rx_status = *status; 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci /* TODO: trace rx packet */ 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci /* PN for multicast packets are not validate in HW, 247362306a36Sopenharmony_ci * so skip 802.3 rx path 247462306a36Sopenharmony_ci * Also, fast_rx expects the STA to be authorized, hence 247562306a36Sopenharmony_ci * eapol packets are sent in slow path. 247662306a36Sopenharmony_ci */ 247762306a36Sopenharmony_ci if (decap == DP_RX_DECAP_TYPE_ETHERNET2_DIX && !is_eapol && 247862306a36Sopenharmony_ci !(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED)) 247962306a36Sopenharmony_ci rx_status->flag |= RX_FLAG_8023; 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_ci ieee80211_rx_napi(ar->hw, pubsta, msdu, napi); 248262306a36Sopenharmony_ci} 248362306a36Sopenharmony_ci 248462306a36Sopenharmony_cistatic int ath12k_dp_rx_process_msdu(struct ath12k *ar, 248562306a36Sopenharmony_ci struct sk_buff *msdu, 248662306a36Sopenharmony_ci struct sk_buff_head *msdu_list, 248762306a36Sopenharmony_ci struct ieee80211_rx_status *rx_status) 248862306a36Sopenharmony_ci{ 248962306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 249062306a36Sopenharmony_ci struct hal_rx_desc *rx_desc, *lrx_desc; 249162306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb; 249262306a36Sopenharmony_ci struct sk_buff *last_buf; 249362306a36Sopenharmony_ci u8 l3_pad_bytes; 249462306a36Sopenharmony_ci u16 msdu_len; 249562306a36Sopenharmony_ci int ret; 249662306a36Sopenharmony_ci u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci last_buf = ath12k_dp_rx_get_msdu_last_buf(msdu_list, msdu); 249962306a36Sopenharmony_ci if (!last_buf) { 250062306a36Sopenharmony_ci ath12k_warn(ab, 250162306a36Sopenharmony_ci "No valid Rx buffer to access MSDU_END tlv\n"); 250262306a36Sopenharmony_ci ret = -EIO; 250362306a36Sopenharmony_ci goto free_out; 250462306a36Sopenharmony_ci } 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci rx_desc = (struct hal_rx_desc *)msdu->data; 250762306a36Sopenharmony_ci lrx_desc = (struct hal_rx_desc *)last_buf->data; 250862306a36Sopenharmony_ci if (!ath12k_dp_rx_h_msdu_done(ab, lrx_desc)) { 250962306a36Sopenharmony_ci ath12k_warn(ab, "msdu_done bit in msdu_end is not set\n"); 251062306a36Sopenharmony_ci ret = -EIO; 251162306a36Sopenharmony_ci goto free_out; 251262306a36Sopenharmony_ci } 251362306a36Sopenharmony_ci 251462306a36Sopenharmony_ci rxcb = ATH12K_SKB_RXCB(msdu); 251562306a36Sopenharmony_ci rxcb->rx_desc = rx_desc; 251662306a36Sopenharmony_ci msdu_len = ath12k_dp_rx_h_msdu_len(ab, lrx_desc); 251762306a36Sopenharmony_ci l3_pad_bytes = ath12k_dp_rx_h_l3pad(ab, lrx_desc); 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci if (rxcb->is_frag) { 252062306a36Sopenharmony_ci skb_pull(msdu, hal_rx_desc_sz); 252162306a36Sopenharmony_ci } else if (!rxcb->is_continuation) { 252262306a36Sopenharmony_ci if ((msdu_len + hal_rx_desc_sz) > DP_RX_BUFFER_SIZE) { 252362306a36Sopenharmony_ci ret = -EINVAL; 252462306a36Sopenharmony_ci ath12k_warn(ab, "invalid msdu len %u\n", msdu_len); 252562306a36Sopenharmony_ci ath12k_dbg_dump(ab, ATH12K_DBG_DATA, NULL, "", rx_desc, 252662306a36Sopenharmony_ci sizeof(*rx_desc)); 252762306a36Sopenharmony_ci goto free_out; 252862306a36Sopenharmony_ci } 252962306a36Sopenharmony_ci skb_put(msdu, hal_rx_desc_sz + l3_pad_bytes + msdu_len); 253062306a36Sopenharmony_ci skb_pull(msdu, hal_rx_desc_sz + l3_pad_bytes); 253162306a36Sopenharmony_ci } else { 253262306a36Sopenharmony_ci ret = ath12k_dp_rx_msdu_coalesce(ar, msdu_list, 253362306a36Sopenharmony_ci msdu, last_buf, 253462306a36Sopenharmony_ci l3_pad_bytes, msdu_len); 253562306a36Sopenharmony_ci if (ret) { 253662306a36Sopenharmony_ci ath12k_warn(ab, 253762306a36Sopenharmony_ci "failed to coalesce msdu rx buffer%d\n", ret); 253862306a36Sopenharmony_ci goto free_out; 253962306a36Sopenharmony_ci } 254062306a36Sopenharmony_ci } 254162306a36Sopenharmony_ci 254262306a36Sopenharmony_ci ath12k_dp_rx_h_ppdu(ar, rx_desc, rx_status); 254362306a36Sopenharmony_ci ath12k_dp_rx_h_mpdu(ar, msdu, rx_desc, rx_status); 254462306a36Sopenharmony_ci 254562306a36Sopenharmony_ci rx_status->flag |= RX_FLAG_SKIP_MONITOR | RX_FLAG_DUP_VALIDATED; 254662306a36Sopenharmony_ci 254762306a36Sopenharmony_ci return 0; 254862306a36Sopenharmony_ci 254962306a36Sopenharmony_cifree_out: 255062306a36Sopenharmony_ci return ret; 255162306a36Sopenharmony_ci} 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_cistatic void ath12k_dp_rx_process_received_packets(struct ath12k_base *ab, 255462306a36Sopenharmony_ci struct napi_struct *napi, 255562306a36Sopenharmony_ci struct sk_buff_head *msdu_list, 255662306a36Sopenharmony_ci int ring_id) 255762306a36Sopenharmony_ci{ 255862306a36Sopenharmony_ci struct ieee80211_rx_status rx_status = {0}; 255962306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb; 256062306a36Sopenharmony_ci struct sk_buff *msdu; 256162306a36Sopenharmony_ci struct ath12k *ar; 256262306a36Sopenharmony_ci u8 mac_id, pdev_id; 256362306a36Sopenharmony_ci int ret; 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci if (skb_queue_empty(msdu_list)) 256662306a36Sopenharmony_ci return; 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci rcu_read_lock(); 256962306a36Sopenharmony_ci 257062306a36Sopenharmony_ci while ((msdu = __skb_dequeue(msdu_list))) { 257162306a36Sopenharmony_ci rxcb = ATH12K_SKB_RXCB(msdu); 257262306a36Sopenharmony_ci mac_id = rxcb->mac_id; 257362306a36Sopenharmony_ci pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); 257462306a36Sopenharmony_ci ar = ab->pdevs[pdev_id].ar; 257562306a36Sopenharmony_ci if (!rcu_dereference(ab->pdevs_active[pdev_id])) { 257662306a36Sopenharmony_ci dev_kfree_skb_any(msdu); 257762306a36Sopenharmony_ci continue; 257862306a36Sopenharmony_ci } 257962306a36Sopenharmony_ci 258062306a36Sopenharmony_ci if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { 258162306a36Sopenharmony_ci dev_kfree_skb_any(msdu); 258262306a36Sopenharmony_ci continue; 258362306a36Sopenharmony_ci } 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci ret = ath12k_dp_rx_process_msdu(ar, msdu, msdu_list, &rx_status); 258662306a36Sopenharmony_ci if (ret) { 258762306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_DATA, 258862306a36Sopenharmony_ci "Unable to process msdu %d", ret); 258962306a36Sopenharmony_ci dev_kfree_skb_any(msdu); 259062306a36Sopenharmony_ci continue; 259162306a36Sopenharmony_ci } 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_ci ath12k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_status); 259462306a36Sopenharmony_ci } 259562306a36Sopenharmony_ci 259662306a36Sopenharmony_ci rcu_read_unlock(); 259762306a36Sopenharmony_ci} 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_ciint ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id, 260062306a36Sopenharmony_ci struct napi_struct *napi, int budget) 260162306a36Sopenharmony_ci{ 260262306a36Sopenharmony_ci struct ath12k_rx_desc_info *desc_info; 260362306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 260462306a36Sopenharmony_ci struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; 260562306a36Sopenharmony_ci struct hal_reo_dest_ring *desc; 260662306a36Sopenharmony_ci int num_buffs_reaped = 0; 260762306a36Sopenharmony_ci struct sk_buff_head msdu_list; 260862306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb; 260962306a36Sopenharmony_ci int total_msdu_reaped = 0; 261062306a36Sopenharmony_ci struct hal_srng *srng; 261162306a36Sopenharmony_ci struct sk_buff *msdu; 261262306a36Sopenharmony_ci bool done = false; 261362306a36Sopenharmony_ci int mac_id; 261462306a36Sopenharmony_ci u64 desc_va; 261562306a36Sopenharmony_ci 261662306a36Sopenharmony_ci __skb_queue_head_init(&msdu_list); 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_ci srng = &ab->hal.srng_list[dp->reo_dst_ring[ring_id].ring_id]; 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_ci spin_lock_bh(&srng->lock); 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_citry_again: 262362306a36Sopenharmony_ci ath12k_hal_srng_access_begin(ab, srng); 262462306a36Sopenharmony_ci 262562306a36Sopenharmony_ci while ((desc = ath12k_hal_srng_dst_get_next_entry(ab, srng))) { 262662306a36Sopenharmony_ci enum hal_reo_dest_ring_push_reason push_reason; 262762306a36Sopenharmony_ci u32 cookie; 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci cookie = le32_get_bits(desc->buf_addr_info.info1, 263062306a36Sopenharmony_ci BUFFER_ADDR_INFO1_SW_COOKIE); 263162306a36Sopenharmony_ci 263262306a36Sopenharmony_ci mac_id = le32_get_bits(desc->info0, 263362306a36Sopenharmony_ci HAL_REO_DEST_RING_INFO0_SRC_LINK_ID); 263462306a36Sopenharmony_ci 263562306a36Sopenharmony_ci desc_va = ((u64)le32_to_cpu(desc->buf_va_hi) << 32 | 263662306a36Sopenharmony_ci le32_to_cpu(desc->buf_va_lo)); 263762306a36Sopenharmony_ci desc_info = (struct ath12k_rx_desc_info *)((unsigned long)desc_va); 263862306a36Sopenharmony_ci 263962306a36Sopenharmony_ci /* retry manual desc retrieval */ 264062306a36Sopenharmony_ci if (!desc_info) { 264162306a36Sopenharmony_ci desc_info = ath12k_dp_get_rx_desc(ab, cookie); 264262306a36Sopenharmony_ci if (!desc_info) { 264362306a36Sopenharmony_ci ath12k_warn(ab, "Invalid cookie in manual desc retrieval"); 264462306a36Sopenharmony_ci continue; 264562306a36Sopenharmony_ci } 264662306a36Sopenharmony_ci } 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci if (desc_info->magic != ATH12K_DP_RX_DESC_MAGIC) 264962306a36Sopenharmony_ci ath12k_warn(ab, "Check HW CC implementation"); 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci msdu = desc_info->skb; 265262306a36Sopenharmony_ci desc_info->skb = NULL; 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_ci spin_lock_bh(&dp->rx_desc_lock); 265562306a36Sopenharmony_ci list_move_tail(&desc_info->list, &dp->rx_desc_free_list); 265662306a36Sopenharmony_ci spin_unlock_bh(&dp->rx_desc_lock); 265762306a36Sopenharmony_ci 265862306a36Sopenharmony_ci rxcb = ATH12K_SKB_RXCB(msdu); 265962306a36Sopenharmony_ci dma_unmap_single(ab->dev, rxcb->paddr, 266062306a36Sopenharmony_ci msdu->len + skb_tailroom(msdu), 266162306a36Sopenharmony_ci DMA_FROM_DEVICE); 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_ci num_buffs_reaped++; 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ci push_reason = le32_get_bits(desc->info0, 266662306a36Sopenharmony_ci HAL_REO_DEST_RING_INFO0_PUSH_REASON); 266762306a36Sopenharmony_ci if (push_reason != 266862306a36Sopenharmony_ci HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) { 266962306a36Sopenharmony_ci dev_kfree_skb_any(msdu); 267062306a36Sopenharmony_ci ab->soc_stats.hal_reo_error[dp->reo_dst_ring[ring_id].ring_id]++; 267162306a36Sopenharmony_ci continue; 267262306a36Sopenharmony_ci } 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_ci rxcb->is_first_msdu = !!(le32_to_cpu(desc->rx_msdu_info.info0) & 267562306a36Sopenharmony_ci RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU); 267662306a36Sopenharmony_ci rxcb->is_last_msdu = !!(le32_to_cpu(desc->rx_msdu_info.info0) & 267762306a36Sopenharmony_ci RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU); 267862306a36Sopenharmony_ci rxcb->is_continuation = !!(le32_to_cpu(desc->rx_msdu_info.info0) & 267962306a36Sopenharmony_ci RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); 268062306a36Sopenharmony_ci rxcb->mac_id = mac_id; 268162306a36Sopenharmony_ci rxcb->peer_id = le32_get_bits(desc->rx_mpdu_info.peer_meta_data, 268262306a36Sopenharmony_ci RX_MPDU_DESC_META_DATA_PEER_ID); 268362306a36Sopenharmony_ci rxcb->tid = le32_get_bits(desc->rx_mpdu_info.info0, 268462306a36Sopenharmony_ci RX_MPDU_DESC_INFO0_TID); 268562306a36Sopenharmony_ci 268662306a36Sopenharmony_ci __skb_queue_tail(&msdu_list, msdu); 268762306a36Sopenharmony_ci 268862306a36Sopenharmony_ci if (!rxcb->is_continuation) { 268962306a36Sopenharmony_ci total_msdu_reaped++; 269062306a36Sopenharmony_ci done = true; 269162306a36Sopenharmony_ci } else { 269262306a36Sopenharmony_ci done = false; 269362306a36Sopenharmony_ci } 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci if (total_msdu_reaped >= budget) 269662306a36Sopenharmony_ci break; 269762306a36Sopenharmony_ci } 269862306a36Sopenharmony_ci 269962306a36Sopenharmony_ci /* Hw might have updated the head pointer after we cached it. 270062306a36Sopenharmony_ci * In this case, even though there are entries in the ring we'll 270162306a36Sopenharmony_ci * get rx_desc NULL. Give the read another try with updated cached 270262306a36Sopenharmony_ci * head pointer so that we can reap complete MPDU in the current 270362306a36Sopenharmony_ci * rx processing. 270462306a36Sopenharmony_ci */ 270562306a36Sopenharmony_ci if (!done && ath12k_hal_srng_dst_num_free(ab, srng, true)) { 270662306a36Sopenharmony_ci ath12k_hal_srng_access_end(ab, srng); 270762306a36Sopenharmony_ci goto try_again; 270862306a36Sopenharmony_ci } 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci ath12k_hal_srng_access_end(ab, srng); 271162306a36Sopenharmony_ci 271262306a36Sopenharmony_ci spin_unlock_bh(&srng->lock); 271362306a36Sopenharmony_ci 271462306a36Sopenharmony_ci if (!total_msdu_reaped) 271562306a36Sopenharmony_ci goto exit; 271662306a36Sopenharmony_ci 271762306a36Sopenharmony_ci /* TODO: Move to implicit BM? */ 271862306a36Sopenharmony_ci ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, num_buffs_reaped, 271962306a36Sopenharmony_ci ab->hw_params->hal_params->rx_buf_rbm, true); 272062306a36Sopenharmony_ci 272162306a36Sopenharmony_ci ath12k_dp_rx_process_received_packets(ab, napi, &msdu_list, 272262306a36Sopenharmony_ci ring_id); 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ciexit: 272562306a36Sopenharmony_ci return total_msdu_reaped; 272662306a36Sopenharmony_ci} 272762306a36Sopenharmony_ci 272862306a36Sopenharmony_cistatic void ath12k_dp_rx_frag_timer(struct timer_list *timer) 272962306a36Sopenharmony_ci{ 273062306a36Sopenharmony_ci struct ath12k_dp_rx_tid *rx_tid = from_timer(rx_tid, timer, frag_timer); 273162306a36Sopenharmony_ci 273262306a36Sopenharmony_ci spin_lock_bh(&rx_tid->ab->base_lock); 273362306a36Sopenharmony_ci if (rx_tid->last_frag_no && 273462306a36Sopenharmony_ci rx_tid->rx_frag_bitmap == GENMASK(rx_tid->last_frag_no, 0)) { 273562306a36Sopenharmony_ci spin_unlock_bh(&rx_tid->ab->base_lock); 273662306a36Sopenharmony_ci return; 273762306a36Sopenharmony_ci } 273862306a36Sopenharmony_ci ath12k_dp_rx_frags_cleanup(rx_tid, true); 273962306a36Sopenharmony_ci spin_unlock_bh(&rx_tid->ab->base_lock); 274062306a36Sopenharmony_ci} 274162306a36Sopenharmony_ci 274262306a36Sopenharmony_ciint ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_id) 274362306a36Sopenharmony_ci{ 274462306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 274562306a36Sopenharmony_ci struct crypto_shash *tfm; 274662306a36Sopenharmony_ci struct ath12k_peer *peer; 274762306a36Sopenharmony_ci struct ath12k_dp_rx_tid *rx_tid; 274862306a36Sopenharmony_ci int i; 274962306a36Sopenharmony_ci 275062306a36Sopenharmony_ci tfm = crypto_alloc_shash("michael_mic", 0, 0); 275162306a36Sopenharmony_ci if (IS_ERR(tfm)) 275262306a36Sopenharmony_ci return PTR_ERR(tfm); 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_ci spin_lock_bh(&ab->base_lock); 275562306a36Sopenharmony_ci 275662306a36Sopenharmony_ci peer = ath12k_peer_find(ab, vdev_id, peer_mac); 275762306a36Sopenharmony_ci if (!peer) { 275862306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 275962306a36Sopenharmony_ci ath12k_warn(ab, "failed to find the peer to set up fragment info\n"); 276062306a36Sopenharmony_ci return -ENOENT; 276162306a36Sopenharmony_ci } 276262306a36Sopenharmony_ci 276362306a36Sopenharmony_ci for (i = 0; i <= IEEE80211_NUM_TIDS; i++) { 276462306a36Sopenharmony_ci rx_tid = &peer->rx_tid[i]; 276562306a36Sopenharmony_ci rx_tid->ab = ab; 276662306a36Sopenharmony_ci timer_setup(&rx_tid->frag_timer, ath12k_dp_rx_frag_timer, 0); 276762306a36Sopenharmony_ci skb_queue_head_init(&rx_tid->rx_frags); 276862306a36Sopenharmony_ci } 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_ci peer->tfm_mmic = tfm; 277162306a36Sopenharmony_ci peer->dp_setup_done = true; 277262306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 277362306a36Sopenharmony_ci 277462306a36Sopenharmony_ci return 0; 277562306a36Sopenharmony_ci} 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_cistatic int ath12k_dp_rx_h_michael_mic(struct crypto_shash *tfm, u8 *key, 277862306a36Sopenharmony_ci struct ieee80211_hdr *hdr, u8 *data, 277962306a36Sopenharmony_ci size_t data_len, u8 *mic) 278062306a36Sopenharmony_ci{ 278162306a36Sopenharmony_ci SHASH_DESC_ON_STACK(desc, tfm); 278262306a36Sopenharmony_ci u8 mic_hdr[16] = {0}; 278362306a36Sopenharmony_ci u8 tid = 0; 278462306a36Sopenharmony_ci int ret; 278562306a36Sopenharmony_ci 278662306a36Sopenharmony_ci if (!tfm) 278762306a36Sopenharmony_ci return -EINVAL; 278862306a36Sopenharmony_ci 278962306a36Sopenharmony_ci desc->tfm = tfm; 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ci ret = crypto_shash_setkey(tfm, key, 8); 279262306a36Sopenharmony_ci if (ret) 279362306a36Sopenharmony_ci goto out; 279462306a36Sopenharmony_ci 279562306a36Sopenharmony_ci ret = crypto_shash_init(desc); 279662306a36Sopenharmony_ci if (ret) 279762306a36Sopenharmony_ci goto out; 279862306a36Sopenharmony_ci 279962306a36Sopenharmony_ci /* TKIP MIC header */ 280062306a36Sopenharmony_ci memcpy(mic_hdr, ieee80211_get_DA(hdr), ETH_ALEN); 280162306a36Sopenharmony_ci memcpy(mic_hdr + ETH_ALEN, ieee80211_get_SA(hdr), ETH_ALEN); 280262306a36Sopenharmony_ci if (ieee80211_is_data_qos(hdr->frame_control)) 280362306a36Sopenharmony_ci tid = ieee80211_get_tid(hdr); 280462306a36Sopenharmony_ci mic_hdr[12] = tid; 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_ci ret = crypto_shash_update(desc, mic_hdr, 16); 280762306a36Sopenharmony_ci if (ret) 280862306a36Sopenharmony_ci goto out; 280962306a36Sopenharmony_ci ret = crypto_shash_update(desc, data, data_len); 281062306a36Sopenharmony_ci if (ret) 281162306a36Sopenharmony_ci goto out; 281262306a36Sopenharmony_ci ret = crypto_shash_final(desc, mic); 281362306a36Sopenharmony_ciout: 281462306a36Sopenharmony_ci shash_desc_zero(desc); 281562306a36Sopenharmony_ci return ret; 281662306a36Sopenharmony_ci} 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_cistatic int ath12k_dp_rx_h_verify_tkip_mic(struct ath12k *ar, struct ath12k_peer *peer, 281962306a36Sopenharmony_ci struct sk_buff *msdu) 282062306a36Sopenharmony_ci{ 282162306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 282262306a36Sopenharmony_ci struct hal_rx_desc *rx_desc = (struct hal_rx_desc *)msdu->data; 282362306a36Sopenharmony_ci struct ieee80211_rx_status *rxs = IEEE80211_SKB_RXCB(msdu); 282462306a36Sopenharmony_ci struct ieee80211_key_conf *key_conf; 282562306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 282662306a36Sopenharmony_ci u8 mic[IEEE80211_CCMP_MIC_LEN]; 282762306a36Sopenharmony_ci int head_len, tail_len, ret; 282862306a36Sopenharmony_ci size_t data_len; 282962306a36Sopenharmony_ci u32 hdr_len, hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; 283062306a36Sopenharmony_ci u8 *key, *data; 283162306a36Sopenharmony_ci u8 key_idx; 283262306a36Sopenharmony_ci 283362306a36Sopenharmony_ci if (ath12k_dp_rx_h_enctype(ab, rx_desc) != HAL_ENCRYPT_TYPE_TKIP_MIC) 283462306a36Sopenharmony_ci return 0; 283562306a36Sopenharmony_ci 283662306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)(msdu->data + hal_rx_desc_sz); 283762306a36Sopenharmony_ci hdr_len = ieee80211_hdrlen(hdr->frame_control); 283862306a36Sopenharmony_ci head_len = hdr_len + hal_rx_desc_sz + IEEE80211_TKIP_IV_LEN; 283962306a36Sopenharmony_ci tail_len = IEEE80211_CCMP_MIC_LEN + IEEE80211_TKIP_ICV_LEN + FCS_LEN; 284062306a36Sopenharmony_ci 284162306a36Sopenharmony_ci if (!is_multicast_ether_addr(hdr->addr1)) 284262306a36Sopenharmony_ci key_idx = peer->ucast_keyidx; 284362306a36Sopenharmony_ci else 284462306a36Sopenharmony_ci key_idx = peer->mcast_keyidx; 284562306a36Sopenharmony_ci 284662306a36Sopenharmony_ci key_conf = peer->keys[key_idx]; 284762306a36Sopenharmony_ci 284862306a36Sopenharmony_ci data = msdu->data + head_len; 284962306a36Sopenharmony_ci data_len = msdu->len - head_len - tail_len; 285062306a36Sopenharmony_ci key = &key_conf->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]; 285162306a36Sopenharmony_ci 285262306a36Sopenharmony_ci ret = ath12k_dp_rx_h_michael_mic(peer->tfm_mmic, key, hdr, data, data_len, mic); 285362306a36Sopenharmony_ci if (ret || memcmp(mic, data + data_len, IEEE80211_CCMP_MIC_LEN)) 285462306a36Sopenharmony_ci goto mic_fail; 285562306a36Sopenharmony_ci 285662306a36Sopenharmony_ci return 0; 285762306a36Sopenharmony_ci 285862306a36Sopenharmony_cimic_fail: 285962306a36Sopenharmony_ci (ATH12K_SKB_RXCB(msdu))->is_first_msdu = true; 286062306a36Sopenharmony_ci (ATH12K_SKB_RXCB(msdu))->is_last_msdu = true; 286162306a36Sopenharmony_ci 286262306a36Sopenharmony_ci rxs->flag |= RX_FLAG_MMIC_ERROR | RX_FLAG_MMIC_STRIPPED | 286362306a36Sopenharmony_ci RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED; 286462306a36Sopenharmony_ci skb_pull(msdu, hal_rx_desc_sz); 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_ci ath12k_dp_rx_h_ppdu(ar, rx_desc, rxs); 286762306a36Sopenharmony_ci ath12k_dp_rx_h_undecap(ar, msdu, rx_desc, 286862306a36Sopenharmony_ci HAL_ENCRYPT_TYPE_TKIP_MIC, rxs, true); 286962306a36Sopenharmony_ci ieee80211_rx(ar->hw, msdu); 287062306a36Sopenharmony_ci return -EINVAL; 287162306a36Sopenharmony_ci} 287262306a36Sopenharmony_ci 287362306a36Sopenharmony_cistatic void ath12k_dp_rx_h_undecap_frag(struct ath12k *ar, struct sk_buff *msdu, 287462306a36Sopenharmony_ci enum hal_encrypt_type enctype, u32 flags) 287562306a36Sopenharmony_ci{ 287662306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 287762306a36Sopenharmony_ci size_t hdr_len; 287862306a36Sopenharmony_ci size_t crypto_len; 287962306a36Sopenharmony_ci u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_ci if (!flags) 288262306a36Sopenharmony_ci return; 288362306a36Sopenharmony_ci 288462306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)(msdu->data + hal_rx_desc_sz); 288562306a36Sopenharmony_ci 288662306a36Sopenharmony_ci if (flags & RX_FLAG_MIC_STRIPPED) 288762306a36Sopenharmony_ci skb_trim(msdu, msdu->len - 288862306a36Sopenharmony_ci ath12k_dp_rx_crypto_mic_len(ar, enctype)); 288962306a36Sopenharmony_ci 289062306a36Sopenharmony_ci if (flags & RX_FLAG_ICV_STRIPPED) 289162306a36Sopenharmony_ci skb_trim(msdu, msdu->len - 289262306a36Sopenharmony_ci ath12k_dp_rx_crypto_icv_len(ar, enctype)); 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci if (flags & RX_FLAG_IV_STRIPPED) { 289562306a36Sopenharmony_ci hdr_len = ieee80211_hdrlen(hdr->frame_control); 289662306a36Sopenharmony_ci crypto_len = ath12k_dp_rx_crypto_param_len(ar, enctype); 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_ci memmove(msdu->data + hal_rx_desc_sz + crypto_len, 289962306a36Sopenharmony_ci msdu->data + hal_rx_desc_sz, hdr_len); 290062306a36Sopenharmony_ci skb_pull(msdu, crypto_len); 290162306a36Sopenharmony_ci } 290262306a36Sopenharmony_ci} 290362306a36Sopenharmony_ci 290462306a36Sopenharmony_cistatic int ath12k_dp_rx_h_defrag(struct ath12k *ar, 290562306a36Sopenharmony_ci struct ath12k_peer *peer, 290662306a36Sopenharmony_ci struct ath12k_dp_rx_tid *rx_tid, 290762306a36Sopenharmony_ci struct sk_buff **defrag_skb) 290862306a36Sopenharmony_ci{ 290962306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 291062306a36Sopenharmony_ci struct hal_rx_desc *rx_desc; 291162306a36Sopenharmony_ci struct sk_buff *skb, *first_frag, *last_frag; 291262306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 291362306a36Sopenharmony_ci enum hal_encrypt_type enctype; 291462306a36Sopenharmony_ci bool is_decrypted = false; 291562306a36Sopenharmony_ci int msdu_len = 0; 291662306a36Sopenharmony_ci int extra_space; 291762306a36Sopenharmony_ci u32 flags, hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; 291862306a36Sopenharmony_ci 291962306a36Sopenharmony_ci first_frag = skb_peek(&rx_tid->rx_frags); 292062306a36Sopenharmony_ci last_frag = skb_peek_tail(&rx_tid->rx_frags); 292162306a36Sopenharmony_ci 292262306a36Sopenharmony_ci skb_queue_walk(&rx_tid->rx_frags, skb) { 292362306a36Sopenharmony_ci flags = 0; 292462306a36Sopenharmony_ci rx_desc = (struct hal_rx_desc *)skb->data; 292562306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)(skb->data + hal_rx_desc_sz); 292662306a36Sopenharmony_ci 292762306a36Sopenharmony_ci enctype = ath12k_dp_rx_h_enctype(ab, rx_desc); 292862306a36Sopenharmony_ci if (enctype != HAL_ENCRYPT_TYPE_OPEN) 292962306a36Sopenharmony_ci is_decrypted = ath12k_dp_rx_h_is_decrypted(ab, 293062306a36Sopenharmony_ci rx_desc); 293162306a36Sopenharmony_ci 293262306a36Sopenharmony_ci if (is_decrypted) { 293362306a36Sopenharmony_ci if (skb != first_frag) 293462306a36Sopenharmony_ci flags |= RX_FLAG_IV_STRIPPED; 293562306a36Sopenharmony_ci if (skb != last_frag) 293662306a36Sopenharmony_ci flags |= RX_FLAG_ICV_STRIPPED | 293762306a36Sopenharmony_ci RX_FLAG_MIC_STRIPPED; 293862306a36Sopenharmony_ci } 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_ci /* RX fragments are always raw packets */ 294162306a36Sopenharmony_ci if (skb != last_frag) 294262306a36Sopenharmony_ci skb_trim(skb, skb->len - FCS_LEN); 294362306a36Sopenharmony_ci ath12k_dp_rx_h_undecap_frag(ar, skb, enctype, flags); 294462306a36Sopenharmony_ci 294562306a36Sopenharmony_ci if (skb != first_frag) 294662306a36Sopenharmony_ci skb_pull(skb, hal_rx_desc_sz + 294762306a36Sopenharmony_ci ieee80211_hdrlen(hdr->frame_control)); 294862306a36Sopenharmony_ci msdu_len += skb->len; 294962306a36Sopenharmony_ci } 295062306a36Sopenharmony_ci 295162306a36Sopenharmony_ci extra_space = msdu_len - (DP_RX_BUFFER_SIZE + skb_tailroom(first_frag)); 295262306a36Sopenharmony_ci if (extra_space > 0 && 295362306a36Sopenharmony_ci (pskb_expand_head(first_frag, 0, extra_space, GFP_ATOMIC) < 0)) 295462306a36Sopenharmony_ci return -ENOMEM; 295562306a36Sopenharmony_ci 295662306a36Sopenharmony_ci __skb_unlink(first_frag, &rx_tid->rx_frags); 295762306a36Sopenharmony_ci while ((skb = __skb_dequeue(&rx_tid->rx_frags))) { 295862306a36Sopenharmony_ci skb_put_data(first_frag, skb->data, skb->len); 295962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 296062306a36Sopenharmony_ci } 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)(first_frag->data + hal_rx_desc_sz); 296362306a36Sopenharmony_ci hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); 296462306a36Sopenharmony_ci ATH12K_SKB_RXCB(first_frag)->is_frag = 1; 296562306a36Sopenharmony_ci 296662306a36Sopenharmony_ci if (ath12k_dp_rx_h_verify_tkip_mic(ar, peer, first_frag)) 296762306a36Sopenharmony_ci first_frag = NULL; 296862306a36Sopenharmony_ci 296962306a36Sopenharmony_ci *defrag_skb = first_frag; 297062306a36Sopenharmony_ci return 0; 297162306a36Sopenharmony_ci} 297262306a36Sopenharmony_ci 297362306a36Sopenharmony_cistatic int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar, 297462306a36Sopenharmony_ci struct ath12k_dp_rx_tid *rx_tid, 297562306a36Sopenharmony_ci struct sk_buff *defrag_skb) 297662306a36Sopenharmony_ci{ 297762306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 297862306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 297962306a36Sopenharmony_ci struct hal_rx_desc *rx_desc = (struct hal_rx_desc *)defrag_skb->data; 298062306a36Sopenharmony_ci struct hal_reo_entrance_ring *reo_ent_ring; 298162306a36Sopenharmony_ci struct hal_reo_dest_ring *reo_dest_ring; 298262306a36Sopenharmony_ci struct dp_link_desc_bank *link_desc_banks; 298362306a36Sopenharmony_ci struct hal_rx_msdu_link *msdu_link; 298462306a36Sopenharmony_ci struct hal_rx_msdu_details *msdu0; 298562306a36Sopenharmony_ci struct hal_srng *srng; 298662306a36Sopenharmony_ci dma_addr_t link_paddr, buf_paddr; 298762306a36Sopenharmony_ci u32 desc_bank, msdu_info, msdu_ext_info, mpdu_info; 298862306a36Sopenharmony_ci u32 cookie, hal_rx_desc_sz, dest_ring_info0; 298962306a36Sopenharmony_ci int ret; 299062306a36Sopenharmony_ci struct ath12k_rx_desc_info *desc_info; 299162306a36Sopenharmony_ci u8 dst_ind; 299262306a36Sopenharmony_ci 299362306a36Sopenharmony_ci hal_rx_desc_sz = ab->hw_params->hal_desc_sz; 299462306a36Sopenharmony_ci link_desc_banks = dp->link_desc_banks; 299562306a36Sopenharmony_ci reo_dest_ring = rx_tid->dst_ring_desc; 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci ath12k_hal_rx_reo_ent_paddr_get(ab, &reo_dest_ring->buf_addr_info, 299862306a36Sopenharmony_ci &link_paddr, &cookie); 299962306a36Sopenharmony_ci desc_bank = u32_get_bits(cookie, DP_LINK_DESC_BANK_MASK); 300062306a36Sopenharmony_ci 300162306a36Sopenharmony_ci msdu_link = (struct hal_rx_msdu_link *)(link_desc_banks[desc_bank].vaddr + 300262306a36Sopenharmony_ci (link_paddr - link_desc_banks[desc_bank].paddr)); 300362306a36Sopenharmony_ci msdu0 = &msdu_link->msdu_link[0]; 300462306a36Sopenharmony_ci msdu_ext_info = le32_to_cpu(msdu0->rx_msdu_ext_info.info0); 300562306a36Sopenharmony_ci dst_ind = u32_get_bits(msdu_ext_info, RX_MSDU_EXT_DESC_INFO0_REO_DEST_IND); 300662306a36Sopenharmony_ci 300762306a36Sopenharmony_ci memset(msdu0, 0, sizeof(*msdu0)); 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_ci msdu_info = u32_encode_bits(1, RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU) | 301062306a36Sopenharmony_ci u32_encode_bits(1, RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU) | 301162306a36Sopenharmony_ci u32_encode_bits(0, RX_MSDU_DESC_INFO0_MSDU_CONTINUATION) | 301262306a36Sopenharmony_ci u32_encode_bits(defrag_skb->len - hal_rx_desc_sz, 301362306a36Sopenharmony_ci RX_MSDU_DESC_INFO0_MSDU_LENGTH) | 301462306a36Sopenharmony_ci u32_encode_bits(1, RX_MSDU_DESC_INFO0_VALID_SA) | 301562306a36Sopenharmony_ci u32_encode_bits(1, RX_MSDU_DESC_INFO0_VALID_DA); 301662306a36Sopenharmony_ci msdu0->rx_msdu_info.info0 = cpu_to_le32(msdu_info); 301762306a36Sopenharmony_ci msdu0->rx_msdu_ext_info.info0 = cpu_to_le32(msdu_ext_info); 301862306a36Sopenharmony_ci 301962306a36Sopenharmony_ci /* change msdu len in hal rx desc */ 302062306a36Sopenharmony_ci ath12k_dp_rxdesc_set_msdu_len(ab, rx_desc, defrag_skb->len - hal_rx_desc_sz); 302162306a36Sopenharmony_ci 302262306a36Sopenharmony_ci buf_paddr = dma_map_single(ab->dev, defrag_skb->data, 302362306a36Sopenharmony_ci defrag_skb->len + skb_tailroom(defrag_skb), 302462306a36Sopenharmony_ci DMA_FROM_DEVICE); 302562306a36Sopenharmony_ci if (dma_mapping_error(ab->dev, buf_paddr)) 302662306a36Sopenharmony_ci return -ENOMEM; 302762306a36Sopenharmony_ci 302862306a36Sopenharmony_ci spin_lock_bh(&dp->rx_desc_lock); 302962306a36Sopenharmony_ci desc_info = list_first_entry_or_null(&dp->rx_desc_free_list, 303062306a36Sopenharmony_ci struct ath12k_rx_desc_info, 303162306a36Sopenharmony_ci list); 303262306a36Sopenharmony_ci if (!desc_info) { 303362306a36Sopenharmony_ci spin_unlock_bh(&dp->rx_desc_lock); 303462306a36Sopenharmony_ci ath12k_warn(ab, "failed to find rx desc for reinject\n"); 303562306a36Sopenharmony_ci ret = -ENOMEM; 303662306a36Sopenharmony_ci goto err_unmap_dma; 303762306a36Sopenharmony_ci } 303862306a36Sopenharmony_ci 303962306a36Sopenharmony_ci desc_info->skb = defrag_skb; 304062306a36Sopenharmony_ci 304162306a36Sopenharmony_ci list_del(&desc_info->list); 304262306a36Sopenharmony_ci list_add_tail(&desc_info->list, &dp->rx_desc_used_list); 304362306a36Sopenharmony_ci spin_unlock_bh(&dp->rx_desc_lock); 304462306a36Sopenharmony_ci 304562306a36Sopenharmony_ci ATH12K_SKB_RXCB(defrag_skb)->paddr = buf_paddr; 304662306a36Sopenharmony_ci 304762306a36Sopenharmony_ci ath12k_hal_rx_buf_addr_info_set(&msdu0->buf_addr_info, buf_paddr, 304862306a36Sopenharmony_ci desc_info->cookie, 304962306a36Sopenharmony_ci HAL_RX_BUF_RBM_SW3_BM); 305062306a36Sopenharmony_ci 305162306a36Sopenharmony_ci /* Fill mpdu details into reo entrance ring */ 305262306a36Sopenharmony_ci srng = &ab->hal.srng_list[dp->reo_reinject_ring.ring_id]; 305362306a36Sopenharmony_ci 305462306a36Sopenharmony_ci spin_lock_bh(&srng->lock); 305562306a36Sopenharmony_ci ath12k_hal_srng_access_begin(ab, srng); 305662306a36Sopenharmony_ci 305762306a36Sopenharmony_ci reo_ent_ring = ath12k_hal_srng_src_get_next_entry(ab, srng); 305862306a36Sopenharmony_ci if (!reo_ent_ring) { 305962306a36Sopenharmony_ci ath12k_hal_srng_access_end(ab, srng); 306062306a36Sopenharmony_ci spin_unlock_bh(&srng->lock); 306162306a36Sopenharmony_ci ret = -ENOSPC; 306262306a36Sopenharmony_ci goto err_free_desc; 306362306a36Sopenharmony_ci } 306462306a36Sopenharmony_ci memset(reo_ent_ring, 0, sizeof(*reo_ent_ring)); 306562306a36Sopenharmony_ci 306662306a36Sopenharmony_ci ath12k_hal_rx_buf_addr_info_set(&reo_ent_ring->buf_addr_info, link_paddr, 306762306a36Sopenharmony_ci cookie, 306862306a36Sopenharmony_ci HAL_RX_BUF_RBM_WBM_CHIP0_IDLE_DESC_LIST); 306962306a36Sopenharmony_ci 307062306a36Sopenharmony_ci mpdu_info = u32_encode_bits(1, RX_MPDU_DESC_INFO0_MSDU_COUNT) | 307162306a36Sopenharmony_ci u32_encode_bits(0, RX_MPDU_DESC_INFO0_FRAG_FLAG) | 307262306a36Sopenharmony_ci u32_encode_bits(1, RX_MPDU_DESC_INFO0_RAW_MPDU) | 307362306a36Sopenharmony_ci u32_encode_bits(1, RX_MPDU_DESC_INFO0_VALID_PN) | 307462306a36Sopenharmony_ci u32_encode_bits(rx_tid->tid, RX_MPDU_DESC_INFO0_TID); 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_ci reo_ent_ring->rx_mpdu_info.info0 = cpu_to_le32(mpdu_info); 307762306a36Sopenharmony_ci reo_ent_ring->rx_mpdu_info.peer_meta_data = 307862306a36Sopenharmony_ci reo_dest_ring->rx_mpdu_info.peer_meta_data; 307962306a36Sopenharmony_ci 308062306a36Sopenharmony_ci /* Firmware expects physical address to be filled in queue_addr_lo in 308162306a36Sopenharmony_ci * the MLO scenario and in case of non MLO peer meta data needs to be 308262306a36Sopenharmony_ci * filled. 308362306a36Sopenharmony_ci * TODO: Need to handle for MLO scenario. 308462306a36Sopenharmony_ci */ 308562306a36Sopenharmony_ci reo_ent_ring->queue_addr_lo = reo_dest_ring->rx_mpdu_info.peer_meta_data; 308662306a36Sopenharmony_ci reo_ent_ring->info0 = le32_encode_bits(dst_ind, 308762306a36Sopenharmony_ci HAL_REO_ENTR_RING_INFO0_DEST_IND); 308862306a36Sopenharmony_ci 308962306a36Sopenharmony_ci reo_ent_ring->info1 = le32_encode_bits(rx_tid->cur_sn, 309062306a36Sopenharmony_ci HAL_REO_ENTR_RING_INFO1_MPDU_SEQ_NUM); 309162306a36Sopenharmony_ci dest_ring_info0 = le32_get_bits(reo_dest_ring->info0, 309262306a36Sopenharmony_ci HAL_REO_DEST_RING_INFO0_SRC_LINK_ID); 309362306a36Sopenharmony_ci reo_ent_ring->info2 = 309462306a36Sopenharmony_ci cpu_to_le32(u32_get_bits(dest_ring_info0, 309562306a36Sopenharmony_ci HAL_REO_ENTR_RING_INFO2_SRC_LINK_ID)); 309662306a36Sopenharmony_ci 309762306a36Sopenharmony_ci ath12k_hal_srng_access_end(ab, srng); 309862306a36Sopenharmony_ci spin_unlock_bh(&srng->lock); 309962306a36Sopenharmony_ci 310062306a36Sopenharmony_ci return 0; 310162306a36Sopenharmony_ci 310262306a36Sopenharmony_cierr_free_desc: 310362306a36Sopenharmony_ci spin_lock_bh(&dp->rx_desc_lock); 310462306a36Sopenharmony_ci list_del(&desc_info->list); 310562306a36Sopenharmony_ci list_add_tail(&desc_info->list, &dp->rx_desc_free_list); 310662306a36Sopenharmony_ci desc_info->skb = NULL; 310762306a36Sopenharmony_ci spin_unlock_bh(&dp->rx_desc_lock); 310862306a36Sopenharmony_cierr_unmap_dma: 310962306a36Sopenharmony_ci dma_unmap_single(ab->dev, buf_paddr, defrag_skb->len + skb_tailroom(defrag_skb), 311062306a36Sopenharmony_ci DMA_FROM_DEVICE); 311162306a36Sopenharmony_ci return ret; 311262306a36Sopenharmony_ci} 311362306a36Sopenharmony_ci 311462306a36Sopenharmony_cistatic int ath12k_dp_rx_h_cmp_frags(struct ath12k_base *ab, 311562306a36Sopenharmony_ci struct sk_buff *a, struct sk_buff *b) 311662306a36Sopenharmony_ci{ 311762306a36Sopenharmony_ci int frag1, frag2; 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci frag1 = ath12k_dp_rx_h_frag_no(ab, a); 312062306a36Sopenharmony_ci frag2 = ath12k_dp_rx_h_frag_no(ab, b); 312162306a36Sopenharmony_ci 312262306a36Sopenharmony_ci return frag1 - frag2; 312362306a36Sopenharmony_ci} 312462306a36Sopenharmony_ci 312562306a36Sopenharmony_cistatic void ath12k_dp_rx_h_sort_frags(struct ath12k_base *ab, 312662306a36Sopenharmony_ci struct sk_buff_head *frag_list, 312762306a36Sopenharmony_ci struct sk_buff *cur_frag) 312862306a36Sopenharmony_ci{ 312962306a36Sopenharmony_ci struct sk_buff *skb; 313062306a36Sopenharmony_ci int cmp; 313162306a36Sopenharmony_ci 313262306a36Sopenharmony_ci skb_queue_walk(frag_list, skb) { 313362306a36Sopenharmony_ci cmp = ath12k_dp_rx_h_cmp_frags(ab, skb, cur_frag); 313462306a36Sopenharmony_ci if (cmp < 0) 313562306a36Sopenharmony_ci continue; 313662306a36Sopenharmony_ci __skb_queue_before(frag_list, skb, cur_frag); 313762306a36Sopenharmony_ci return; 313862306a36Sopenharmony_ci } 313962306a36Sopenharmony_ci __skb_queue_tail(frag_list, cur_frag); 314062306a36Sopenharmony_ci} 314162306a36Sopenharmony_ci 314262306a36Sopenharmony_cistatic u64 ath12k_dp_rx_h_get_pn(struct ath12k *ar, struct sk_buff *skb) 314362306a36Sopenharmony_ci{ 314462306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 314562306a36Sopenharmony_ci u64 pn = 0; 314662306a36Sopenharmony_ci u8 *ehdr; 314762306a36Sopenharmony_ci u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; 314862306a36Sopenharmony_ci 314962306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)(skb->data + hal_rx_desc_sz); 315062306a36Sopenharmony_ci ehdr = skb->data + hal_rx_desc_sz + ieee80211_hdrlen(hdr->frame_control); 315162306a36Sopenharmony_ci 315262306a36Sopenharmony_ci pn = ehdr[0]; 315362306a36Sopenharmony_ci pn |= (u64)ehdr[1] << 8; 315462306a36Sopenharmony_ci pn |= (u64)ehdr[4] << 16; 315562306a36Sopenharmony_ci pn |= (u64)ehdr[5] << 24; 315662306a36Sopenharmony_ci pn |= (u64)ehdr[6] << 32; 315762306a36Sopenharmony_ci pn |= (u64)ehdr[7] << 40; 315862306a36Sopenharmony_ci 315962306a36Sopenharmony_ci return pn; 316062306a36Sopenharmony_ci} 316162306a36Sopenharmony_ci 316262306a36Sopenharmony_cistatic bool 316362306a36Sopenharmony_ciath12k_dp_rx_h_defrag_validate_incr_pn(struct ath12k *ar, struct ath12k_dp_rx_tid *rx_tid) 316462306a36Sopenharmony_ci{ 316562306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 316662306a36Sopenharmony_ci enum hal_encrypt_type encrypt_type; 316762306a36Sopenharmony_ci struct sk_buff *first_frag, *skb; 316862306a36Sopenharmony_ci struct hal_rx_desc *desc; 316962306a36Sopenharmony_ci u64 last_pn; 317062306a36Sopenharmony_ci u64 cur_pn; 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ci first_frag = skb_peek(&rx_tid->rx_frags); 317362306a36Sopenharmony_ci desc = (struct hal_rx_desc *)first_frag->data; 317462306a36Sopenharmony_ci 317562306a36Sopenharmony_ci encrypt_type = ath12k_dp_rx_h_enctype(ab, desc); 317662306a36Sopenharmony_ci if (encrypt_type != HAL_ENCRYPT_TYPE_CCMP_128 && 317762306a36Sopenharmony_ci encrypt_type != HAL_ENCRYPT_TYPE_CCMP_256 && 317862306a36Sopenharmony_ci encrypt_type != HAL_ENCRYPT_TYPE_GCMP_128 && 317962306a36Sopenharmony_ci encrypt_type != HAL_ENCRYPT_TYPE_AES_GCMP_256) 318062306a36Sopenharmony_ci return true; 318162306a36Sopenharmony_ci 318262306a36Sopenharmony_ci last_pn = ath12k_dp_rx_h_get_pn(ar, first_frag); 318362306a36Sopenharmony_ci skb_queue_walk(&rx_tid->rx_frags, skb) { 318462306a36Sopenharmony_ci if (skb == first_frag) 318562306a36Sopenharmony_ci continue; 318662306a36Sopenharmony_ci 318762306a36Sopenharmony_ci cur_pn = ath12k_dp_rx_h_get_pn(ar, skb); 318862306a36Sopenharmony_ci if (cur_pn != last_pn + 1) 318962306a36Sopenharmony_ci return false; 319062306a36Sopenharmony_ci last_pn = cur_pn; 319162306a36Sopenharmony_ci } 319262306a36Sopenharmony_ci return true; 319362306a36Sopenharmony_ci} 319462306a36Sopenharmony_ci 319562306a36Sopenharmony_cistatic int ath12k_dp_rx_frag_h_mpdu(struct ath12k *ar, 319662306a36Sopenharmony_ci struct sk_buff *msdu, 319762306a36Sopenharmony_ci struct hal_reo_dest_ring *ring_desc) 319862306a36Sopenharmony_ci{ 319962306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 320062306a36Sopenharmony_ci struct hal_rx_desc *rx_desc; 320162306a36Sopenharmony_ci struct ath12k_peer *peer; 320262306a36Sopenharmony_ci struct ath12k_dp_rx_tid *rx_tid; 320362306a36Sopenharmony_ci struct sk_buff *defrag_skb = NULL; 320462306a36Sopenharmony_ci u32 peer_id; 320562306a36Sopenharmony_ci u16 seqno, frag_no; 320662306a36Sopenharmony_ci u8 tid; 320762306a36Sopenharmony_ci int ret = 0; 320862306a36Sopenharmony_ci bool more_frags; 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_ci rx_desc = (struct hal_rx_desc *)msdu->data; 321162306a36Sopenharmony_ci peer_id = ath12k_dp_rx_h_peer_id(ab, rx_desc); 321262306a36Sopenharmony_ci tid = ath12k_dp_rx_h_tid(ab, rx_desc); 321362306a36Sopenharmony_ci seqno = ath12k_dp_rx_h_seq_no(ab, rx_desc); 321462306a36Sopenharmony_ci frag_no = ath12k_dp_rx_h_frag_no(ab, msdu); 321562306a36Sopenharmony_ci more_frags = ath12k_dp_rx_h_more_frags(ab, msdu); 321662306a36Sopenharmony_ci 321762306a36Sopenharmony_ci if (!ath12k_dp_rx_h_seq_ctrl_valid(ab, rx_desc) || 321862306a36Sopenharmony_ci !ath12k_dp_rx_h_fc_valid(ab, rx_desc) || 321962306a36Sopenharmony_ci tid > IEEE80211_NUM_TIDS) 322062306a36Sopenharmony_ci return -EINVAL; 322162306a36Sopenharmony_ci 322262306a36Sopenharmony_ci /* received unfragmented packet in reo 322362306a36Sopenharmony_ci * exception ring, this shouldn't happen 322462306a36Sopenharmony_ci * as these packets typically come from 322562306a36Sopenharmony_ci * reo2sw srngs. 322662306a36Sopenharmony_ci */ 322762306a36Sopenharmony_ci if (WARN_ON_ONCE(!frag_no && !more_frags)) 322862306a36Sopenharmony_ci return -EINVAL; 322962306a36Sopenharmony_ci 323062306a36Sopenharmony_ci spin_lock_bh(&ab->base_lock); 323162306a36Sopenharmony_ci peer = ath12k_peer_find_by_id(ab, peer_id); 323262306a36Sopenharmony_ci if (!peer) { 323362306a36Sopenharmony_ci ath12k_warn(ab, "failed to find the peer to de-fragment received fragment peer_id %d\n", 323462306a36Sopenharmony_ci peer_id); 323562306a36Sopenharmony_ci ret = -ENOENT; 323662306a36Sopenharmony_ci goto out_unlock; 323762306a36Sopenharmony_ci } 323862306a36Sopenharmony_ci 323962306a36Sopenharmony_ci if (!peer->dp_setup_done) { 324062306a36Sopenharmony_ci ath12k_warn(ab, "The peer %pM [%d] has uninitialized datapath\n", 324162306a36Sopenharmony_ci peer->addr, peer_id); 324262306a36Sopenharmony_ci ret = -ENOENT; 324362306a36Sopenharmony_ci goto out_unlock; 324462306a36Sopenharmony_ci } 324562306a36Sopenharmony_ci 324662306a36Sopenharmony_ci rx_tid = &peer->rx_tid[tid]; 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_ci if ((!skb_queue_empty(&rx_tid->rx_frags) && seqno != rx_tid->cur_sn) || 324962306a36Sopenharmony_ci skb_queue_empty(&rx_tid->rx_frags)) { 325062306a36Sopenharmony_ci /* Flush stored fragments and start a new sequence */ 325162306a36Sopenharmony_ci ath12k_dp_rx_frags_cleanup(rx_tid, true); 325262306a36Sopenharmony_ci rx_tid->cur_sn = seqno; 325362306a36Sopenharmony_ci } 325462306a36Sopenharmony_ci 325562306a36Sopenharmony_ci if (rx_tid->rx_frag_bitmap & BIT(frag_no)) { 325662306a36Sopenharmony_ci /* Fragment already present */ 325762306a36Sopenharmony_ci ret = -EINVAL; 325862306a36Sopenharmony_ci goto out_unlock; 325962306a36Sopenharmony_ci } 326062306a36Sopenharmony_ci 326162306a36Sopenharmony_ci if ((!rx_tid->rx_frag_bitmap || frag_no > __fls(rx_tid->rx_frag_bitmap))) 326262306a36Sopenharmony_ci __skb_queue_tail(&rx_tid->rx_frags, msdu); 326362306a36Sopenharmony_ci else 326462306a36Sopenharmony_ci ath12k_dp_rx_h_sort_frags(ab, &rx_tid->rx_frags, msdu); 326562306a36Sopenharmony_ci 326662306a36Sopenharmony_ci rx_tid->rx_frag_bitmap |= BIT(frag_no); 326762306a36Sopenharmony_ci if (!more_frags) 326862306a36Sopenharmony_ci rx_tid->last_frag_no = frag_no; 326962306a36Sopenharmony_ci 327062306a36Sopenharmony_ci if (frag_no == 0) { 327162306a36Sopenharmony_ci rx_tid->dst_ring_desc = kmemdup(ring_desc, 327262306a36Sopenharmony_ci sizeof(*rx_tid->dst_ring_desc), 327362306a36Sopenharmony_ci GFP_ATOMIC); 327462306a36Sopenharmony_ci if (!rx_tid->dst_ring_desc) { 327562306a36Sopenharmony_ci ret = -ENOMEM; 327662306a36Sopenharmony_ci goto out_unlock; 327762306a36Sopenharmony_ci } 327862306a36Sopenharmony_ci } else { 327962306a36Sopenharmony_ci ath12k_dp_rx_link_desc_return(ab, ring_desc, 328062306a36Sopenharmony_ci HAL_WBM_REL_BM_ACT_PUT_IN_IDLE); 328162306a36Sopenharmony_ci } 328262306a36Sopenharmony_ci 328362306a36Sopenharmony_ci if (!rx_tid->last_frag_no || 328462306a36Sopenharmony_ci rx_tid->rx_frag_bitmap != GENMASK(rx_tid->last_frag_no, 0)) { 328562306a36Sopenharmony_ci mod_timer(&rx_tid->frag_timer, jiffies + 328662306a36Sopenharmony_ci ATH12K_DP_RX_FRAGMENT_TIMEOUT_MS); 328762306a36Sopenharmony_ci goto out_unlock; 328862306a36Sopenharmony_ci } 328962306a36Sopenharmony_ci 329062306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 329162306a36Sopenharmony_ci del_timer_sync(&rx_tid->frag_timer); 329262306a36Sopenharmony_ci spin_lock_bh(&ab->base_lock); 329362306a36Sopenharmony_ci 329462306a36Sopenharmony_ci peer = ath12k_peer_find_by_id(ab, peer_id); 329562306a36Sopenharmony_ci if (!peer) 329662306a36Sopenharmony_ci goto err_frags_cleanup; 329762306a36Sopenharmony_ci 329862306a36Sopenharmony_ci if (!ath12k_dp_rx_h_defrag_validate_incr_pn(ar, rx_tid)) 329962306a36Sopenharmony_ci goto err_frags_cleanup; 330062306a36Sopenharmony_ci 330162306a36Sopenharmony_ci if (ath12k_dp_rx_h_defrag(ar, peer, rx_tid, &defrag_skb)) 330262306a36Sopenharmony_ci goto err_frags_cleanup; 330362306a36Sopenharmony_ci 330462306a36Sopenharmony_ci if (!defrag_skb) 330562306a36Sopenharmony_ci goto err_frags_cleanup; 330662306a36Sopenharmony_ci 330762306a36Sopenharmony_ci if (ath12k_dp_rx_h_defrag_reo_reinject(ar, rx_tid, defrag_skb)) 330862306a36Sopenharmony_ci goto err_frags_cleanup; 330962306a36Sopenharmony_ci 331062306a36Sopenharmony_ci ath12k_dp_rx_frags_cleanup(rx_tid, false); 331162306a36Sopenharmony_ci goto out_unlock; 331262306a36Sopenharmony_ci 331362306a36Sopenharmony_cierr_frags_cleanup: 331462306a36Sopenharmony_ci dev_kfree_skb_any(defrag_skb); 331562306a36Sopenharmony_ci ath12k_dp_rx_frags_cleanup(rx_tid, true); 331662306a36Sopenharmony_ciout_unlock: 331762306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 331862306a36Sopenharmony_ci return ret; 331962306a36Sopenharmony_ci} 332062306a36Sopenharmony_ci 332162306a36Sopenharmony_cistatic int 332262306a36Sopenharmony_ciath12k_dp_process_rx_err_buf(struct ath12k *ar, struct hal_reo_dest_ring *desc, 332362306a36Sopenharmony_ci bool drop, u32 cookie) 332462306a36Sopenharmony_ci{ 332562306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 332662306a36Sopenharmony_ci struct sk_buff *msdu; 332762306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb; 332862306a36Sopenharmony_ci struct hal_rx_desc *rx_desc; 332962306a36Sopenharmony_ci u16 msdu_len; 333062306a36Sopenharmony_ci u32 hal_rx_desc_sz = ab->hw_params->hal_desc_sz; 333162306a36Sopenharmony_ci struct ath12k_rx_desc_info *desc_info; 333262306a36Sopenharmony_ci u64 desc_va; 333362306a36Sopenharmony_ci 333462306a36Sopenharmony_ci desc_va = ((u64)le32_to_cpu(desc->buf_va_hi) << 32 | 333562306a36Sopenharmony_ci le32_to_cpu(desc->buf_va_lo)); 333662306a36Sopenharmony_ci desc_info = (struct ath12k_rx_desc_info *)((unsigned long)desc_va); 333762306a36Sopenharmony_ci 333862306a36Sopenharmony_ci /* retry manual desc retrieval */ 333962306a36Sopenharmony_ci if (!desc_info) { 334062306a36Sopenharmony_ci desc_info = ath12k_dp_get_rx_desc(ab, cookie); 334162306a36Sopenharmony_ci if (!desc_info) { 334262306a36Sopenharmony_ci ath12k_warn(ab, "Invalid cookie in manual desc retrieval"); 334362306a36Sopenharmony_ci return -EINVAL; 334462306a36Sopenharmony_ci } 334562306a36Sopenharmony_ci } 334662306a36Sopenharmony_ci 334762306a36Sopenharmony_ci if (desc_info->magic != ATH12K_DP_RX_DESC_MAGIC) 334862306a36Sopenharmony_ci ath12k_warn(ab, " RX Exception, Check HW CC implementation"); 334962306a36Sopenharmony_ci 335062306a36Sopenharmony_ci msdu = desc_info->skb; 335162306a36Sopenharmony_ci desc_info->skb = NULL; 335262306a36Sopenharmony_ci spin_lock_bh(&ab->dp.rx_desc_lock); 335362306a36Sopenharmony_ci list_move_tail(&desc_info->list, &ab->dp.rx_desc_free_list); 335462306a36Sopenharmony_ci spin_unlock_bh(&ab->dp.rx_desc_lock); 335562306a36Sopenharmony_ci 335662306a36Sopenharmony_ci rxcb = ATH12K_SKB_RXCB(msdu); 335762306a36Sopenharmony_ci dma_unmap_single(ar->ab->dev, rxcb->paddr, 335862306a36Sopenharmony_ci msdu->len + skb_tailroom(msdu), 335962306a36Sopenharmony_ci DMA_FROM_DEVICE); 336062306a36Sopenharmony_ci 336162306a36Sopenharmony_ci if (drop) { 336262306a36Sopenharmony_ci dev_kfree_skb_any(msdu); 336362306a36Sopenharmony_ci return 0; 336462306a36Sopenharmony_ci } 336562306a36Sopenharmony_ci 336662306a36Sopenharmony_ci rcu_read_lock(); 336762306a36Sopenharmony_ci if (!rcu_dereference(ar->ab->pdevs_active[ar->pdev_idx])) { 336862306a36Sopenharmony_ci dev_kfree_skb_any(msdu); 336962306a36Sopenharmony_ci goto exit; 337062306a36Sopenharmony_ci } 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_ci if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { 337362306a36Sopenharmony_ci dev_kfree_skb_any(msdu); 337462306a36Sopenharmony_ci goto exit; 337562306a36Sopenharmony_ci } 337662306a36Sopenharmony_ci 337762306a36Sopenharmony_ci rx_desc = (struct hal_rx_desc *)msdu->data; 337862306a36Sopenharmony_ci msdu_len = ath12k_dp_rx_h_msdu_len(ar->ab, rx_desc); 337962306a36Sopenharmony_ci if ((msdu_len + hal_rx_desc_sz) > DP_RX_BUFFER_SIZE) { 338062306a36Sopenharmony_ci ath12k_warn(ar->ab, "invalid msdu leng %u", msdu_len); 338162306a36Sopenharmony_ci ath12k_dbg_dump(ar->ab, ATH12K_DBG_DATA, NULL, "", rx_desc, 338262306a36Sopenharmony_ci sizeof(*rx_desc)); 338362306a36Sopenharmony_ci dev_kfree_skb_any(msdu); 338462306a36Sopenharmony_ci goto exit; 338562306a36Sopenharmony_ci } 338662306a36Sopenharmony_ci 338762306a36Sopenharmony_ci skb_put(msdu, hal_rx_desc_sz + msdu_len); 338862306a36Sopenharmony_ci 338962306a36Sopenharmony_ci if (ath12k_dp_rx_frag_h_mpdu(ar, msdu, desc)) { 339062306a36Sopenharmony_ci dev_kfree_skb_any(msdu); 339162306a36Sopenharmony_ci ath12k_dp_rx_link_desc_return(ar->ab, desc, 339262306a36Sopenharmony_ci HAL_WBM_REL_BM_ACT_PUT_IN_IDLE); 339362306a36Sopenharmony_ci } 339462306a36Sopenharmony_ciexit: 339562306a36Sopenharmony_ci rcu_read_unlock(); 339662306a36Sopenharmony_ci return 0; 339762306a36Sopenharmony_ci} 339862306a36Sopenharmony_ci 339962306a36Sopenharmony_ciint ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, 340062306a36Sopenharmony_ci int budget) 340162306a36Sopenharmony_ci{ 340262306a36Sopenharmony_ci u32 msdu_cookies[HAL_NUM_RX_MSDUS_PER_LINK_DESC]; 340362306a36Sopenharmony_ci struct dp_link_desc_bank *link_desc_banks; 340462306a36Sopenharmony_ci enum hal_rx_buf_return_buf_manager rbm; 340562306a36Sopenharmony_ci struct hal_rx_msdu_link *link_desc_va; 340662306a36Sopenharmony_ci int tot_n_bufs_reaped, quota, ret, i; 340762306a36Sopenharmony_ci struct hal_reo_dest_ring *reo_desc; 340862306a36Sopenharmony_ci struct dp_rxdma_ring *rx_ring; 340962306a36Sopenharmony_ci struct dp_srng *reo_except; 341062306a36Sopenharmony_ci u32 desc_bank, num_msdus; 341162306a36Sopenharmony_ci struct hal_srng *srng; 341262306a36Sopenharmony_ci struct ath12k_dp *dp; 341362306a36Sopenharmony_ci int mac_id; 341462306a36Sopenharmony_ci struct ath12k *ar; 341562306a36Sopenharmony_ci dma_addr_t paddr; 341662306a36Sopenharmony_ci bool is_frag; 341762306a36Sopenharmony_ci bool drop = false; 341862306a36Sopenharmony_ci int pdev_id; 341962306a36Sopenharmony_ci 342062306a36Sopenharmony_ci tot_n_bufs_reaped = 0; 342162306a36Sopenharmony_ci quota = budget; 342262306a36Sopenharmony_ci 342362306a36Sopenharmony_ci dp = &ab->dp; 342462306a36Sopenharmony_ci reo_except = &dp->reo_except_ring; 342562306a36Sopenharmony_ci link_desc_banks = dp->link_desc_banks; 342662306a36Sopenharmony_ci 342762306a36Sopenharmony_ci srng = &ab->hal.srng_list[reo_except->ring_id]; 342862306a36Sopenharmony_ci 342962306a36Sopenharmony_ci spin_lock_bh(&srng->lock); 343062306a36Sopenharmony_ci 343162306a36Sopenharmony_ci ath12k_hal_srng_access_begin(ab, srng); 343262306a36Sopenharmony_ci 343362306a36Sopenharmony_ci while (budget && 343462306a36Sopenharmony_ci (reo_desc = ath12k_hal_srng_dst_get_next_entry(ab, srng))) { 343562306a36Sopenharmony_ci ab->soc_stats.err_ring_pkts++; 343662306a36Sopenharmony_ci ret = ath12k_hal_desc_reo_parse_err(ab, reo_desc, &paddr, 343762306a36Sopenharmony_ci &desc_bank); 343862306a36Sopenharmony_ci if (ret) { 343962306a36Sopenharmony_ci ath12k_warn(ab, "failed to parse error reo desc %d\n", 344062306a36Sopenharmony_ci ret); 344162306a36Sopenharmony_ci continue; 344262306a36Sopenharmony_ci } 344362306a36Sopenharmony_ci link_desc_va = link_desc_banks[desc_bank].vaddr + 344462306a36Sopenharmony_ci (paddr - link_desc_banks[desc_bank].paddr); 344562306a36Sopenharmony_ci ath12k_hal_rx_msdu_link_info_get(link_desc_va, &num_msdus, msdu_cookies, 344662306a36Sopenharmony_ci &rbm); 344762306a36Sopenharmony_ci if (rbm != HAL_RX_BUF_RBM_WBM_CHIP0_IDLE_DESC_LIST && 344862306a36Sopenharmony_ci rbm != HAL_RX_BUF_RBM_SW3_BM && 344962306a36Sopenharmony_ci rbm != ab->hw_params->hal_params->rx_buf_rbm) { 345062306a36Sopenharmony_ci ab->soc_stats.invalid_rbm++; 345162306a36Sopenharmony_ci ath12k_warn(ab, "invalid return buffer manager %d\n", rbm); 345262306a36Sopenharmony_ci ath12k_dp_rx_link_desc_return(ab, reo_desc, 345362306a36Sopenharmony_ci HAL_WBM_REL_BM_ACT_REL_MSDU); 345462306a36Sopenharmony_ci continue; 345562306a36Sopenharmony_ci } 345662306a36Sopenharmony_ci 345762306a36Sopenharmony_ci is_frag = !!(le32_to_cpu(reo_desc->rx_mpdu_info.info0) & 345862306a36Sopenharmony_ci RX_MPDU_DESC_INFO0_FRAG_FLAG); 345962306a36Sopenharmony_ci 346062306a36Sopenharmony_ci /* Process only rx fragments with one msdu per link desc below, and drop 346162306a36Sopenharmony_ci * msdu's indicated due to error reasons. 346262306a36Sopenharmony_ci */ 346362306a36Sopenharmony_ci if (!is_frag || num_msdus > 1) { 346462306a36Sopenharmony_ci drop = true; 346562306a36Sopenharmony_ci /* Return the link desc back to wbm idle list */ 346662306a36Sopenharmony_ci ath12k_dp_rx_link_desc_return(ab, reo_desc, 346762306a36Sopenharmony_ci HAL_WBM_REL_BM_ACT_PUT_IN_IDLE); 346862306a36Sopenharmony_ci } 346962306a36Sopenharmony_ci 347062306a36Sopenharmony_ci for (i = 0; i < num_msdus; i++) { 347162306a36Sopenharmony_ci mac_id = le32_get_bits(reo_desc->info0, 347262306a36Sopenharmony_ci HAL_REO_DEST_RING_INFO0_SRC_LINK_ID); 347362306a36Sopenharmony_ci 347462306a36Sopenharmony_ci pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); 347562306a36Sopenharmony_ci ar = ab->pdevs[pdev_id].ar; 347662306a36Sopenharmony_ci 347762306a36Sopenharmony_ci if (!ath12k_dp_process_rx_err_buf(ar, reo_desc, drop, 347862306a36Sopenharmony_ci msdu_cookies[i])) 347962306a36Sopenharmony_ci tot_n_bufs_reaped++; 348062306a36Sopenharmony_ci } 348162306a36Sopenharmony_ci 348262306a36Sopenharmony_ci if (tot_n_bufs_reaped >= quota) { 348362306a36Sopenharmony_ci tot_n_bufs_reaped = quota; 348462306a36Sopenharmony_ci goto exit; 348562306a36Sopenharmony_ci } 348662306a36Sopenharmony_ci 348762306a36Sopenharmony_ci budget = quota - tot_n_bufs_reaped; 348862306a36Sopenharmony_ci } 348962306a36Sopenharmony_ci 349062306a36Sopenharmony_ciexit: 349162306a36Sopenharmony_ci ath12k_hal_srng_access_end(ab, srng); 349262306a36Sopenharmony_ci 349362306a36Sopenharmony_ci spin_unlock_bh(&srng->lock); 349462306a36Sopenharmony_ci 349562306a36Sopenharmony_ci rx_ring = &dp->rx_refill_buf_ring; 349662306a36Sopenharmony_ci 349762306a36Sopenharmony_ci ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, tot_n_bufs_reaped, 349862306a36Sopenharmony_ci ab->hw_params->hal_params->rx_buf_rbm, true); 349962306a36Sopenharmony_ci 350062306a36Sopenharmony_ci return tot_n_bufs_reaped; 350162306a36Sopenharmony_ci} 350262306a36Sopenharmony_ci 350362306a36Sopenharmony_cistatic void ath12k_dp_rx_null_q_desc_sg_drop(struct ath12k *ar, 350462306a36Sopenharmony_ci int msdu_len, 350562306a36Sopenharmony_ci struct sk_buff_head *msdu_list) 350662306a36Sopenharmony_ci{ 350762306a36Sopenharmony_ci struct sk_buff *skb, *tmp; 350862306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb; 350962306a36Sopenharmony_ci int n_buffs; 351062306a36Sopenharmony_ci 351162306a36Sopenharmony_ci n_buffs = DIV_ROUND_UP(msdu_len, 351262306a36Sopenharmony_ci (DP_RX_BUFFER_SIZE - ar->ab->hw_params->hal_desc_sz)); 351362306a36Sopenharmony_ci 351462306a36Sopenharmony_ci skb_queue_walk_safe(msdu_list, skb, tmp) { 351562306a36Sopenharmony_ci rxcb = ATH12K_SKB_RXCB(skb); 351662306a36Sopenharmony_ci if (rxcb->err_rel_src == HAL_WBM_REL_SRC_MODULE_REO && 351762306a36Sopenharmony_ci rxcb->err_code == HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO) { 351862306a36Sopenharmony_ci if (!n_buffs) 351962306a36Sopenharmony_ci break; 352062306a36Sopenharmony_ci __skb_unlink(skb, msdu_list); 352162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 352262306a36Sopenharmony_ci n_buffs--; 352362306a36Sopenharmony_ci } 352462306a36Sopenharmony_ci } 352562306a36Sopenharmony_ci} 352662306a36Sopenharmony_ci 352762306a36Sopenharmony_cistatic int ath12k_dp_rx_h_null_q_desc(struct ath12k *ar, struct sk_buff *msdu, 352862306a36Sopenharmony_ci struct ieee80211_rx_status *status, 352962306a36Sopenharmony_ci struct sk_buff_head *msdu_list) 353062306a36Sopenharmony_ci{ 353162306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 353262306a36Sopenharmony_ci u16 msdu_len, peer_id; 353362306a36Sopenharmony_ci struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data; 353462306a36Sopenharmony_ci u8 l3pad_bytes; 353562306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); 353662306a36Sopenharmony_ci u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; 353762306a36Sopenharmony_ci 353862306a36Sopenharmony_ci msdu_len = ath12k_dp_rx_h_msdu_len(ab, desc); 353962306a36Sopenharmony_ci peer_id = ath12k_dp_rx_h_peer_id(ab, desc); 354062306a36Sopenharmony_ci 354162306a36Sopenharmony_ci spin_lock(&ab->base_lock); 354262306a36Sopenharmony_ci if (!ath12k_peer_find_by_id(ab, peer_id)) { 354362306a36Sopenharmony_ci spin_unlock(&ab->base_lock); 354462306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_DATA, "invalid peer id received in wbm err pkt%d\n", 354562306a36Sopenharmony_ci peer_id); 354662306a36Sopenharmony_ci return -EINVAL; 354762306a36Sopenharmony_ci } 354862306a36Sopenharmony_ci spin_unlock(&ab->base_lock); 354962306a36Sopenharmony_ci 355062306a36Sopenharmony_ci if (!rxcb->is_frag && ((msdu_len + hal_rx_desc_sz) > DP_RX_BUFFER_SIZE)) { 355162306a36Sopenharmony_ci /* First buffer will be freed by the caller, so deduct it's length */ 355262306a36Sopenharmony_ci msdu_len = msdu_len - (DP_RX_BUFFER_SIZE - hal_rx_desc_sz); 355362306a36Sopenharmony_ci ath12k_dp_rx_null_q_desc_sg_drop(ar, msdu_len, msdu_list); 355462306a36Sopenharmony_ci return -EINVAL; 355562306a36Sopenharmony_ci } 355662306a36Sopenharmony_ci 355762306a36Sopenharmony_ci /* Even after cleaning up the sg buffers in the msdu list with above check 355862306a36Sopenharmony_ci * any msdu received with continuation flag needs to be dropped as invalid. 355962306a36Sopenharmony_ci * This protects against some random err frame with continuation flag. 356062306a36Sopenharmony_ci */ 356162306a36Sopenharmony_ci if (rxcb->is_continuation) 356262306a36Sopenharmony_ci return -EINVAL; 356362306a36Sopenharmony_ci 356462306a36Sopenharmony_ci if (!ath12k_dp_rx_h_msdu_done(ab, desc)) { 356562306a36Sopenharmony_ci ath12k_warn(ar->ab, 356662306a36Sopenharmony_ci "msdu_done bit not set in null_q_des processing\n"); 356762306a36Sopenharmony_ci __skb_queue_purge(msdu_list); 356862306a36Sopenharmony_ci return -EIO; 356962306a36Sopenharmony_ci } 357062306a36Sopenharmony_ci 357162306a36Sopenharmony_ci /* Handle NULL queue descriptor violations arising out a missing 357262306a36Sopenharmony_ci * REO queue for a given peer or a given TID. This typically 357362306a36Sopenharmony_ci * may happen if a packet is received on a QOS enabled TID before the 357462306a36Sopenharmony_ci * ADDBA negotiation for that TID, when the TID queue is setup. Or 357562306a36Sopenharmony_ci * it may also happen for MC/BC frames if they are not routed to the 357662306a36Sopenharmony_ci * non-QOS TID queue, in the absence of any other default TID queue. 357762306a36Sopenharmony_ci * This error can show up both in a REO destination or WBM release ring. 357862306a36Sopenharmony_ci */ 357962306a36Sopenharmony_ci 358062306a36Sopenharmony_ci if (rxcb->is_frag) { 358162306a36Sopenharmony_ci skb_pull(msdu, hal_rx_desc_sz); 358262306a36Sopenharmony_ci } else { 358362306a36Sopenharmony_ci l3pad_bytes = ath12k_dp_rx_h_l3pad(ab, desc); 358462306a36Sopenharmony_ci 358562306a36Sopenharmony_ci if ((hal_rx_desc_sz + l3pad_bytes + msdu_len) > DP_RX_BUFFER_SIZE) 358662306a36Sopenharmony_ci return -EINVAL; 358762306a36Sopenharmony_ci 358862306a36Sopenharmony_ci skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len); 358962306a36Sopenharmony_ci skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes); 359062306a36Sopenharmony_ci } 359162306a36Sopenharmony_ci ath12k_dp_rx_h_ppdu(ar, desc, status); 359262306a36Sopenharmony_ci 359362306a36Sopenharmony_ci ath12k_dp_rx_h_mpdu(ar, msdu, desc, status); 359462306a36Sopenharmony_ci 359562306a36Sopenharmony_ci rxcb->tid = ath12k_dp_rx_h_tid(ab, desc); 359662306a36Sopenharmony_ci 359762306a36Sopenharmony_ci /* Please note that caller will having the access to msdu and completing 359862306a36Sopenharmony_ci * rx with mac80211. Need not worry about cleaning up amsdu_list. 359962306a36Sopenharmony_ci */ 360062306a36Sopenharmony_ci 360162306a36Sopenharmony_ci return 0; 360262306a36Sopenharmony_ci} 360362306a36Sopenharmony_ci 360462306a36Sopenharmony_cistatic bool ath12k_dp_rx_h_reo_err(struct ath12k *ar, struct sk_buff *msdu, 360562306a36Sopenharmony_ci struct ieee80211_rx_status *status, 360662306a36Sopenharmony_ci struct sk_buff_head *msdu_list) 360762306a36Sopenharmony_ci{ 360862306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); 360962306a36Sopenharmony_ci bool drop = false; 361062306a36Sopenharmony_ci 361162306a36Sopenharmony_ci ar->ab->soc_stats.reo_error[rxcb->err_code]++; 361262306a36Sopenharmony_ci 361362306a36Sopenharmony_ci switch (rxcb->err_code) { 361462306a36Sopenharmony_ci case HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO: 361562306a36Sopenharmony_ci if (ath12k_dp_rx_h_null_q_desc(ar, msdu, status, msdu_list)) 361662306a36Sopenharmony_ci drop = true; 361762306a36Sopenharmony_ci break; 361862306a36Sopenharmony_ci case HAL_REO_DEST_RING_ERROR_CODE_PN_CHECK_FAILED: 361962306a36Sopenharmony_ci /* TODO: Do not drop PN failed packets in the driver; 362062306a36Sopenharmony_ci * instead, it is good to drop such packets in mac80211 362162306a36Sopenharmony_ci * after incrementing the replay counters. 362262306a36Sopenharmony_ci */ 362362306a36Sopenharmony_ci fallthrough; 362462306a36Sopenharmony_ci default: 362562306a36Sopenharmony_ci /* TODO: Review other errors and process them to mac80211 362662306a36Sopenharmony_ci * as appropriate. 362762306a36Sopenharmony_ci */ 362862306a36Sopenharmony_ci drop = true; 362962306a36Sopenharmony_ci break; 363062306a36Sopenharmony_ci } 363162306a36Sopenharmony_ci 363262306a36Sopenharmony_ci return drop; 363362306a36Sopenharmony_ci} 363462306a36Sopenharmony_ci 363562306a36Sopenharmony_cistatic void ath12k_dp_rx_h_tkip_mic_err(struct ath12k *ar, struct sk_buff *msdu, 363662306a36Sopenharmony_ci struct ieee80211_rx_status *status) 363762306a36Sopenharmony_ci{ 363862306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 363962306a36Sopenharmony_ci u16 msdu_len; 364062306a36Sopenharmony_ci struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data; 364162306a36Sopenharmony_ci u8 l3pad_bytes; 364262306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); 364362306a36Sopenharmony_ci u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; 364462306a36Sopenharmony_ci 364562306a36Sopenharmony_ci rxcb->is_first_msdu = ath12k_dp_rx_h_first_msdu(ab, desc); 364662306a36Sopenharmony_ci rxcb->is_last_msdu = ath12k_dp_rx_h_last_msdu(ab, desc); 364762306a36Sopenharmony_ci 364862306a36Sopenharmony_ci l3pad_bytes = ath12k_dp_rx_h_l3pad(ab, desc); 364962306a36Sopenharmony_ci msdu_len = ath12k_dp_rx_h_msdu_len(ab, desc); 365062306a36Sopenharmony_ci skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len); 365162306a36Sopenharmony_ci skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes); 365262306a36Sopenharmony_ci 365362306a36Sopenharmony_ci ath12k_dp_rx_h_ppdu(ar, desc, status); 365462306a36Sopenharmony_ci 365562306a36Sopenharmony_ci status->flag |= (RX_FLAG_MMIC_STRIPPED | RX_FLAG_MMIC_ERROR | 365662306a36Sopenharmony_ci RX_FLAG_DECRYPTED); 365762306a36Sopenharmony_ci 365862306a36Sopenharmony_ci ath12k_dp_rx_h_undecap(ar, msdu, desc, 365962306a36Sopenharmony_ci HAL_ENCRYPT_TYPE_TKIP_MIC, status, false); 366062306a36Sopenharmony_ci} 366162306a36Sopenharmony_ci 366262306a36Sopenharmony_cistatic bool ath12k_dp_rx_h_rxdma_err(struct ath12k *ar, struct sk_buff *msdu, 366362306a36Sopenharmony_ci struct ieee80211_rx_status *status) 366462306a36Sopenharmony_ci{ 366562306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 366662306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); 366762306a36Sopenharmony_ci struct hal_rx_desc *rx_desc = (struct hal_rx_desc *)msdu->data; 366862306a36Sopenharmony_ci bool drop = false; 366962306a36Sopenharmony_ci u32 err_bitmap; 367062306a36Sopenharmony_ci 367162306a36Sopenharmony_ci ar->ab->soc_stats.rxdma_error[rxcb->err_code]++; 367262306a36Sopenharmony_ci 367362306a36Sopenharmony_ci switch (rxcb->err_code) { 367462306a36Sopenharmony_ci case HAL_REO_ENTR_RING_RXDMA_ECODE_DECRYPT_ERR: 367562306a36Sopenharmony_ci case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR: 367662306a36Sopenharmony_ci err_bitmap = ath12k_dp_rx_h_mpdu_err(ab, rx_desc); 367762306a36Sopenharmony_ci if (err_bitmap & HAL_RX_MPDU_ERR_TKIP_MIC) { 367862306a36Sopenharmony_ci ath12k_dp_rx_h_tkip_mic_err(ar, msdu, status); 367962306a36Sopenharmony_ci break; 368062306a36Sopenharmony_ci } 368162306a36Sopenharmony_ci fallthrough; 368262306a36Sopenharmony_ci default: 368362306a36Sopenharmony_ci /* TODO: Review other rxdma error code to check if anything is 368462306a36Sopenharmony_ci * worth reporting to mac80211 368562306a36Sopenharmony_ci */ 368662306a36Sopenharmony_ci drop = true; 368762306a36Sopenharmony_ci break; 368862306a36Sopenharmony_ci } 368962306a36Sopenharmony_ci 369062306a36Sopenharmony_ci return drop; 369162306a36Sopenharmony_ci} 369262306a36Sopenharmony_ci 369362306a36Sopenharmony_cistatic void ath12k_dp_rx_wbm_err(struct ath12k *ar, 369462306a36Sopenharmony_ci struct napi_struct *napi, 369562306a36Sopenharmony_ci struct sk_buff *msdu, 369662306a36Sopenharmony_ci struct sk_buff_head *msdu_list) 369762306a36Sopenharmony_ci{ 369862306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); 369962306a36Sopenharmony_ci struct ieee80211_rx_status rxs = {0}; 370062306a36Sopenharmony_ci bool drop = true; 370162306a36Sopenharmony_ci 370262306a36Sopenharmony_ci switch (rxcb->err_rel_src) { 370362306a36Sopenharmony_ci case HAL_WBM_REL_SRC_MODULE_REO: 370462306a36Sopenharmony_ci drop = ath12k_dp_rx_h_reo_err(ar, msdu, &rxs, msdu_list); 370562306a36Sopenharmony_ci break; 370662306a36Sopenharmony_ci case HAL_WBM_REL_SRC_MODULE_RXDMA: 370762306a36Sopenharmony_ci drop = ath12k_dp_rx_h_rxdma_err(ar, msdu, &rxs); 370862306a36Sopenharmony_ci break; 370962306a36Sopenharmony_ci default: 371062306a36Sopenharmony_ci /* msdu will get freed */ 371162306a36Sopenharmony_ci break; 371262306a36Sopenharmony_ci } 371362306a36Sopenharmony_ci 371462306a36Sopenharmony_ci if (drop) { 371562306a36Sopenharmony_ci dev_kfree_skb_any(msdu); 371662306a36Sopenharmony_ci return; 371762306a36Sopenharmony_ci } 371862306a36Sopenharmony_ci 371962306a36Sopenharmony_ci ath12k_dp_rx_deliver_msdu(ar, napi, msdu, &rxs); 372062306a36Sopenharmony_ci} 372162306a36Sopenharmony_ci 372262306a36Sopenharmony_ciint ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, 372362306a36Sopenharmony_ci struct napi_struct *napi, int budget) 372462306a36Sopenharmony_ci{ 372562306a36Sopenharmony_ci struct ath12k *ar; 372662306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 372762306a36Sopenharmony_ci struct dp_rxdma_ring *rx_ring; 372862306a36Sopenharmony_ci struct hal_rx_wbm_rel_info err_info; 372962306a36Sopenharmony_ci struct hal_srng *srng; 373062306a36Sopenharmony_ci struct sk_buff *msdu; 373162306a36Sopenharmony_ci struct sk_buff_head msdu_list[MAX_RADIOS]; 373262306a36Sopenharmony_ci struct ath12k_skb_rxcb *rxcb; 373362306a36Sopenharmony_ci void *rx_desc; 373462306a36Sopenharmony_ci int mac_id; 373562306a36Sopenharmony_ci int num_buffs_reaped = 0; 373662306a36Sopenharmony_ci struct ath12k_rx_desc_info *desc_info; 373762306a36Sopenharmony_ci int ret, i; 373862306a36Sopenharmony_ci 373962306a36Sopenharmony_ci for (i = 0; i < ab->num_radios; i++) 374062306a36Sopenharmony_ci __skb_queue_head_init(&msdu_list[i]); 374162306a36Sopenharmony_ci 374262306a36Sopenharmony_ci srng = &ab->hal.srng_list[dp->rx_rel_ring.ring_id]; 374362306a36Sopenharmony_ci rx_ring = &dp->rx_refill_buf_ring; 374462306a36Sopenharmony_ci 374562306a36Sopenharmony_ci spin_lock_bh(&srng->lock); 374662306a36Sopenharmony_ci 374762306a36Sopenharmony_ci ath12k_hal_srng_access_begin(ab, srng); 374862306a36Sopenharmony_ci 374962306a36Sopenharmony_ci while (budget) { 375062306a36Sopenharmony_ci rx_desc = ath12k_hal_srng_dst_get_next_entry(ab, srng); 375162306a36Sopenharmony_ci if (!rx_desc) 375262306a36Sopenharmony_ci break; 375362306a36Sopenharmony_ci 375462306a36Sopenharmony_ci ret = ath12k_hal_wbm_desc_parse_err(ab, rx_desc, &err_info); 375562306a36Sopenharmony_ci if (ret) { 375662306a36Sopenharmony_ci ath12k_warn(ab, 375762306a36Sopenharmony_ci "failed to parse rx error in wbm_rel ring desc %d\n", 375862306a36Sopenharmony_ci ret); 375962306a36Sopenharmony_ci continue; 376062306a36Sopenharmony_ci } 376162306a36Sopenharmony_ci 376262306a36Sopenharmony_ci desc_info = (struct ath12k_rx_desc_info *)err_info.rx_desc; 376362306a36Sopenharmony_ci 376462306a36Sopenharmony_ci /* retry manual desc retrieval if hw cc is not done */ 376562306a36Sopenharmony_ci if (!desc_info) { 376662306a36Sopenharmony_ci desc_info = ath12k_dp_get_rx_desc(ab, err_info.cookie); 376762306a36Sopenharmony_ci if (!desc_info) { 376862306a36Sopenharmony_ci ath12k_warn(ab, "Invalid cookie in manual desc retrieval"); 376962306a36Sopenharmony_ci continue; 377062306a36Sopenharmony_ci } 377162306a36Sopenharmony_ci } 377262306a36Sopenharmony_ci 377362306a36Sopenharmony_ci /* FIXME: Extract mac id correctly. Since descs are not tied 377462306a36Sopenharmony_ci * to mac, we can extract from vdev id in ring desc. 377562306a36Sopenharmony_ci */ 377662306a36Sopenharmony_ci mac_id = 0; 377762306a36Sopenharmony_ci 377862306a36Sopenharmony_ci if (desc_info->magic != ATH12K_DP_RX_DESC_MAGIC) 377962306a36Sopenharmony_ci ath12k_warn(ab, "WBM RX err, Check HW CC implementation"); 378062306a36Sopenharmony_ci 378162306a36Sopenharmony_ci msdu = desc_info->skb; 378262306a36Sopenharmony_ci desc_info->skb = NULL; 378362306a36Sopenharmony_ci 378462306a36Sopenharmony_ci spin_lock_bh(&dp->rx_desc_lock); 378562306a36Sopenharmony_ci list_move_tail(&desc_info->list, &dp->rx_desc_free_list); 378662306a36Sopenharmony_ci spin_unlock_bh(&dp->rx_desc_lock); 378762306a36Sopenharmony_ci 378862306a36Sopenharmony_ci rxcb = ATH12K_SKB_RXCB(msdu); 378962306a36Sopenharmony_ci dma_unmap_single(ab->dev, rxcb->paddr, 379062306a36Sopenharmony_ci msdu->len + skb_tailroom(msdu), 379162306a36Sopenharmony_ci DMA_FROM_DEVICE); 379262306a36Sopenharmony_ci 379362306a36Sopenharmony_ci num_buffs_reaped++; 379462306a36Sopenharmony_ci 379562306a36Sopenharmony_ci if (!err_info.continuation) 379662306a36Sopenharmony_ci budget--; 379762306a36Sopenharmony_ci 379862306a36Sopenharmony_ci if (err_info.push_reason != 379962306a36Sopenharmony_ci HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED) { 380062306a36Sopenharmony_ci dev_kfree_skb_any(msdu); 380162306a36Sopenharmony_ci continue; 380262306a36Sopenharmony_ci } 380362306a36Sopenharmony_ci 380462306a36Sopenharmony_ci rxcb->err_rel_src = err_info.err_rel_src; 380562306a36Sopenharmony_ci rxcb->err_code = err_info.err_code; 380662306a36Sopenharmony_ci rxcb->rx_desc = (struct hal_rx_desc *)msdu->data; 380762306a36Sopenharmony_ci __skb_queue_tail(&msdu_list[mac_id], msdu); 380862306a36Sopenharmony_ci 380962306a36Sopenharmony_ci rxcb->is_first_msdu = err_info.first_msdu; 381062306a36Sopenharmony_ci rxcb->is_last_msdu = err_info.last_msdu; 381162306a36Sopenharmony_ci rxcb->is_continuation = err_info.continuation; 381262306a36Sopenharmony_ci } 381362306a36Sopenharmony_ci 381462306a36Sopenharmony_ci ath12k_hal_srng_access_end(ab, srng); 381562306a36Sopenharmony_ci 381662306a36Sopenharmony_ci spin_unlock_bh(&srng->lock); 381762306a36Sopenharmony_ci 381862306a36Sopenharmony_ci if (!num_buffs_reaped) 381962306a36Sopenharmony_ci goto done; 382062306a36Sopenharmony_ci 382162306a36Sopenharmony_ci ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, num_buffs_reaped, 382262306a36Sopenharmony_ci ab->hw_params->hal_params->rx_buf_rbm, true); 382362306a36Sopenharmony_ci 382462306a36Sopenharmony_ci rcu_read_lock(); 382562306a36Sopenharmony_ci for (i = 0; i < ab->num_radios; i++) { 382662306a36Sopenharmony_ci if (!rcu_dereference(ab->pdevs_active[i])) { 382762306a36Sopenharmony_ci __skb_queue_purge(&msdu_list[i]); 382862306a36Sopenharmony_ci continue; 382962306a36Sopenharmony_ci } 383062306a36Sopenharmony_ci 383162306a36Sopenharmony_ci ar = ab->pdevs[i].ar; 383262306a36Sopenharmony_ci 383362306a36Sopenharmony_ci if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { 383462306a36Sopenharmony_ci __skb_queue_purge(&msdu_list[i]); 383562306a36Sopenharmony_ci continue; 383662306a36Sopenharmony_ci } 383762306a36Sopenharmony_ci 383862306a36Sopenharmony_ci while ((msdu = __skb_dequeue(&msdu_list[i])) != NULL) 383962306a36Sopenharmony_ci ath12k_dp_rx_wbm_err(ar, napi, msdu, &msdu_list[i]); 384062306a36Sopenharmony_ci } 384162306a36Sopenharmony_ci rcu_read_unlock(); 384262306a36Sopenharmony_cidone: 384362306a36Sopenharmony_ci return num_buffs_reaped; 384462306a36Sopenharmony_ci} 384562306a36Sopenharmony_ci 384662306a36Sopenharmony_civoid ath12k_dp_rx_process_reo_status(struct ath12k_base *ab) 384762306a36Sopenharmony_ci{ 384862306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 384962306a36Sopenharmony_ci struct hal_tlv_64_hdr *hdr; 385062306a36Sopenharmony_ci struct hal_srng *srng; 385162306a36Sopenharmony_ci struct ath12k_dp_rx_reo_cmd *cmd, *tmp; 385262306a36Sopenharmony_ci bool found = false; 385362306a36Sopenharmony_ci u16 tag; 385462306a36Sopenharmony_ci struct hal_reo_status reo_status; 385562306a36Sopenharmony_ci 385662306a36Sopenharmony_ci srng = &ab->hal.srng_list[dp->reo_status_ring.ring_id]; 385762306a36Sopenharmony_ci 385862306a36Sopenharmony_ci memset(&reo_status, 0, sizeof(reo_status)); 385962306a36Sopenharmony_ci 386062306a36Sopenharmony_ci spin_lock_bh(&srng->lock); 386162306a36Sopenharmony_ci 386262306a36Sopenharmony_ci ath12k_hal_srng_access_begin(ab, srng); 386362306a36Sopenharmony_ci 386462306a36Sopenharmony_ci while ((hdr = ath12k_hal_srng_dst_get_next_entry(ab, srng))) { 386562306a36Sopenharmony_ci tag = u64_get_bits(hdr->tl, HAL_SRNG_TLV_HDR_TAG); 386662306a36Sopenharmony_ci 386762306a36Sopenharmony_ci switch (tag) { 386862306a36Sopenharmony_ci case HAL_REO_GET_QUEUE_STATS_STATUS: 386962306a36Sopenharmony_ci ath12k_hal_reo_status_queue_stats(ab, hdr, 387062306a36Sopenharmony_ci &reo_status); 387162306a36Sopenharmony_ci break; 387262306a36Sopenharmony_ci case HAL_REO_FLUSH_QUEUE_STATUS: 387362306a36Sopenharmony_ci ath12k_hal_reo_flush_queue_status(ab, hdr, 387462306a36Sopenharmony_ci &reo_status); 387562306a36Sopenharmony_ci break; 387662306a36Sopenharmony_ci case HAL_REO_FLUSH_CACHE_STATUS: 387762306a36Sopenharmony_ci ath12k_hal_reo_flush_cache_status(ab, hdr, 387862306a36Sopenharmony_ci &reo_status); 387962306a36Sopenharmony_ci break; 388062306a36Sopenharmony_ci case HAL_REO_UNBLOCK_CACHE_STATUS: 388162306a36Sopenharmony_ci ath12k_hal_reo_unblk_cache_status(ab, hdr, 388262306a36Sopenharmony_ci &reo_status); 388362306a36Sopenharmony_ci break; 388462306a36Sopenharmony_ci case HAL_REO_FLUSH_TIMEOUT_LIST_STATUS: 388562306a36Sopenharmony_ci ath12k_hal_reo_flush_timeout_list_status(ab, hdr, 388662306a36Sopenharmony_ci &reo_status); 388762306a36Sopenharmony_ci break; 388862306a36Sopenharmony_ci case HAL_REO_DESCRIPTOR_THRESHOLD_REACHED_STATUS: 388962306a36Sopenharmony_ci ath12k_hal_reo_desc_thresh_reached_status(ab, hdr, 389062306a36Sopenharmony_ci &reo_status); 389162306a36Sopenharmony_ci break; 389262306a36Sopenharmony_ci case HAL_REO_UPDATE_RX_REO_QUEUE_STATUS: 389362306a36Sopenharmony_ci ath12k_hal_reo_update_rx_reo_queue_status(ab, hdr, 389462306a36Sopenharmony_ci &reo_status); 389562306a36Sopenharmony_ci break; 389662306a36Sopenharmony_ci default: 389762306a36Sopenharmony_ci ath12k_warn(ab, "Unknown reo status type %d\n", tag); 389862306a36Sopenharmony_ci continue; 389962306a36Sopenharmony_ci } 390062306a36Sopenharmony_ci 390162306a36Sopenharmony_ci spin_lock_bh(&dp->reo_cmd_lock); 390262306a36Sopenharmony_ci list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) { 390362306a36Sopenharmony_ci if (reo_status.uniform_hdr.cmd_num == cmd->cmd_num) { 390462306a36Sopenharmony_ci found = true; 390562306a36Sopenharmony_ci list_del(&cmd->list); 390662306a36Sopenharmony_ci break; 390762306a36Sopenharmony_ci } 390862306a36Sopenharmony_ci } 390962306a36Sopenharmony_ci spin_unlock_bh(&dp->reo_cmd_lock); 391062306a36Sopenharmony_ci 391162306a36Sopenharmony_ci if (found) { 391262306a36Sopenharmony_ci cmd->handler(dp, (void *)&cmd->data, 391362306a36Sopenharmony_ci reo_status.uniform_hdr.cmd_status); 391462306a36Sopenharmony_ci kfree(cmd); 391562306a36Sopenharmony_ci } 391662306a36Sopenharmony_ci 391762306a36Sopenharmony_ci found = false; 391862306a36Sopenharmony_ci } 391962306a36Sopenharmony_ci 392062306a36Sopenharmony_ci ath12k_hal_srng_access_end(ab, srng); 392162306a36Sopenharmony_ci 392262306a36Sopenharmony_ci spin_unlock_bh(&srng->lock); 392362306a36Sopenharmony_ci} 392462306a36Sopenharmony_ci 392562306a36Sopenharmony_civoid ath12k_dp_rx_free(struct ath12k_base *ab) 392662306a36Sopenharmony_ci{ 392762306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 392862306a36Sopenharmony_ci int i; 392962306a36Sopenharmony_ci 393062306a36Sopenharmony_ci ath12k_dp_srng_cleanup(ab, &dp->rx_refill_buf_ring.refill_buf_ring); 393162306a36Sopenharmony_ci 393262306a36Sopenharmony_ci for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) { 393362306a36Sopenharmony_ci if (ab->hw_params->rx_mac_buf_ring) 393462306a36Sopenharmony_ci ath12k_dp_srng_cleanup(ab, &dp->rx_mac_buf_ring[i]); 393562306a36Sopenharmony_ci } 393662306a36Sopenharmony_ci 393762306a36Sopenharmony_ci for (i = 0; i < ab->hw_params->num_rxdma_dst_ring; i++) 393862306a36Sopenharmony_ci ath12k_dp_srng_cleanup(ab, &dp->rxdma_err_dst_ring[i]); 393962306a36Sopenharmony_ci 394062306a36Sopenharmony_ci ath12k_dp_srng_cleanup(ab, &dp->rxdma_mon_buf_ring.refill_buf_ring); 394162306a36Sopenharmony_ci ath12k_dp_srng_cleanup(ab, &dp->tx_mon_buf_ring.refill_buf_ring); 394262306a36Sopenharmony_ci 394362306a36Sopenharmony_ci ath12k_dp_rxdma_buf_free(ab); 394462306a36Sopenharmony_ci} 394562306a36Sopenharmony_ci 394662306a36Sopenharmony_civoid ath12k_dp_rx_pdev_free(struct ath12k_base *ab, int mac_id) 394762306a36Sopenharmony_ci{ 394862306a36Sopenharmony_ci struct ath12k *ar = ab->pdevs[mac_id].ar; 394962306a36Sopenharmony_ci 395062306a36Sopenharmony_ci ath12k_dp_rx_pdev_srng_free(ar); 395162306a36Sopenharmony_ci} 395262306a36Sopenharmony_ci 395362306a36Sopenharmony_ciint ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab) 395462306a36Sopenharmony_ci{ 395562306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 395662306a36Sopenharmony_ci struct htt_rx_ring_tlv_filter tlv_filter = {0}; 395762306a36Sopenharmony_ci u32 ring_id; 395862306a36Sopenharmony_ci int ret; 395962306a36Sopenharmony_ci u32 hal_rx_desc_sz = ab->hw_params->hal_desc_sz; 396062306a36Sopenharmony_ci 396162306a36Sopenharmony_ci ring_id = dp->rx_refill_buf_ring.refill_buf_ring.ring_id; 396262306a36Sopenharmony_ci 396362306a36Sopenharmony_ci tlv_filter.rx_filter = HTT_RX_TLV_FLAGS_RXDMA_RING; 396462306a36Sopenharmony_ci tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_BAR; 396562306a36Sopenharmony_ci tlv_filter.pkt_filter_flags3 = HTT_RX_FP_DATA_PKT_FILTER_TLV_FLASG3_MCAST | 396662306a36Sopenharmony_ci HTT_RX_FP_DATA_PKT_FILTER_TLV_FLASG3_UCAST | 396762306a36Sopenharmony_ci HTT_RX_FP_DATA_PKT_FILTER_TLV_FLASG3_NULL_DATA; 396862306a36Sopenharmony_ci tlv_filter.offset_valid = true; 396962306a36Sopenharmony_ci tlv_filter.rx_packet_offset = hal_rx_desc_sz; 397062306a36Sopenharmony_ci 397162306a36Sopenharmony_ci tlv_filter.rx_mpdu_start_offset = 397262306a36Sopenharmony_ci ab->hw_params->hal_ops->rx_desc_get_mpdu_start_offset(); 397362306a36Sopenharmony_ci tlv_filter.rx_msdu_end_offset = 397462306a36Sopenharmony_ci ab->hw_params->hal_ops->rx_desc_get_msdu_end_offset(); 397562306a36Sopenharmony_ci 397662306a36Sopenharmony_ci /* TODO: Selectively subscribe to required qwords within msdu_end 397762306a36Sopenharmony_ci * and mpdu_start and setup the mask in below msg 397862306a36Sopenharmony_ci * and modify the rx_desc struct 397962306a36Sopenharmony_ci */ 398062306a36Sopenharmony_ci ret = ath12k_dp_tx_htt_rx_filter_setup(ab, ring_id, 0, 398162306a36Sopenharmony_ci HAL_RXDMA_BUF, 398262306a36Sopenharmony_ci DP_RXDMA_REFILL_RING_SIZE, 398362306a36Sopenharmony_ci &tlv_filter); 398462306a36Sopenharmony_ci 398562306a36Sopenharmony_ci return ret; 398662306a36Sopenharmony_ci} 398762306a36Sopenharmony_ci 398862306a36Sopenharmony_ciint ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab) 398962306a36Sopenharmony_ci{ 399062306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 399162306a36Sopenharmony_ci struct htt_rx_ring_tlv_filter tlv_filter = {0}; 399262306a36Sopenharmony_ci u32 ring_id; 399362306a36Sopenharmony_ci int ret; 399462306a36Sopenharmony_ci u32 hal_rx_desc_sz = ab->hw_params->hal_desc_sz; 399562306a36Sopenharmony_ci int i; 399662306a36Sopenharmony_ci 399762306a36Sopenharmony_ci ring_id = dp->rx_refill_buf_ring.refill_buf_ring.ring_id; 399862306a36Sopenharmony_ci 399962306a36Sopenharmony_ci tlv_filter.rx_filter = HTT_RX_TLV_FLAGS_RXDMA_RING; 400062306a36Sopenharmony_ci tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_BAR; 400162306a36Sopenharmony_ci tlv_filter.pkt_filter_flags3 = HTT_RX_FP_DATA_PKT_FILTER_TLV_FLASG3_MCAST | 400262306a36Sopenharmony_ci HTT_RX_FP_DATA_PKT_FILTER_TLV_FLASG3_UCAST | 400362306a36Sopenharmony_ci HTT_RX_FP_DATA_PKT_FILTER_TLV_FLASG3_NULL_DATA; 400462306a36Sopenharmony_ci tlv_filter.offset_valid = true; 400562306a36Sopenharmony_ci tlv_filter.rx_packet_offset = hal_rx_desc_sz; 400662306a36Sopenharmony_ci 400762306a36Sopenharmony_ci tlv_filter.rx_header_offset = offsetof(struct hal_rx_desc_wcn7850, pkt_hdr_tlv); 400862306a36Sopenharmony_ci 400962306a36Sopenharmony_ci tlv_filter.rx_mpdu_start_offset = 401062306a36Sopenharmony_ci ab->hw_params->hal_ops->rx_desc_get_mpdu_start_offset(); 401162306a36Sopenharmony_ci tlv_filter.rx_msdu_end_offset = 401262306a36Sopenharmony_ci ab->hw_params->hal_ops->rx_desc_get_msdu_end_offset(); 401362306a36Sopenharmony_ci 401462306a36Sopenharmony_ci /* TODO: Selectively subscribe to required qwords within msdu_end 401562306a36Sopenharmony_ci * and mpdu_start and setup the mask in below msg 401662306a36Sopenharmony_ci * and modify the rx_desc struct 401762306a36Sopenharmony_ci */ 401862306a36Sopenharmony_ci 401962306a36Sopenharmony_ci for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) { 402062306a36Sopenharmony_ci ring_id = dp->rx_mac_buf_ring[i].ring_id; 402162306a36Sopenharmony_ci ret = ath12k_dp_tx_htt_rx_filter_setup(ab, ring_id, i, 402262306a36Sopenharmony_ci HAL_RXDMA_BUF, 402362306a36Sopenharmony_ci DP_RXDMA_REFILL_RING_SIZE, 402462306a36Sopenharmony_ci &tlv_filter); 402562306a36Sopenharmony_ci } 402662306a36Sopenharmony_ci 402762306a36Sopenharmony_ci return ret; 402862306a36Sopenharmony_ci} 402962306a36Sopenharmony_ci 403062306a36Sopenharmony_ciint ath12k_dp_rx_htt_setup(struct ath12k_base *ab) 403162306a36Sopenharmony_ci{ 403262306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 403362306a36Sopenharmony_ci u32 ring_id; 403462306a36Sopenharmony_ci int i, ret; 403562306a36Sopenharmony_ci 403662306a36Sopenharmony_ci /* TODO: Need to verify the HTT setup for QCN9224 */ 403762306a36Sopenharmony_ci ring_id = dp->rx_refill_buf_ring.refill_buf_ring.ring_id; 403862306a36Sopenharmony_ci ret = ath12k_dp_tx_htt_srng_setup(ab, ring_id, 0, HAL_RXDMA_BUF); 403962306a36Sopenharmony_ci if (ret) { 404062306a36Sopenharmony_ci ath12k_warn(ab, "failed to configure rx_refill_buf_ring %d\n", 404162306a36Sopenharmony_ci ret); 404262306a36Sopenharmony_ci return ret; 404362306a36Sopenharmony_ci } 404462306a36Sopenharmony_ci 404562306a36Sopenharmony_ci if (ab->hw_params->rx_mac_buf_ring) { 404662306a36Sopenharmony_ci for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) { 404762306a36Sopenharmony_ci ring_id = dp->rx_mac_buf_ring[i].ring_id; 404862306a36Sopenharmony_ci ret = ath12k_dp_tx_htt_srng_setup(ab, ring_id, 404962306a36Sopenharmony_ci i, HAL_RXDMA_BUF); 405062306a36Sopenharmony_ci if (ret) { 405162306a36Sopenharmony_ci ath12k_warn(ab, "failed to configure rx_mac_buf_ring%d %d\n", 405262306a36Sopenharmony_ci i, ret); 405362306a36Sopenharmony_ci return ret; 405462306a36Sopenharmony_ci } 405562306a36Sopenharmony_ci } 405662306a36Sopenharmony_ci } 405762306a36Sopenharmony_ci 405862306a36Sopenharmony_ci for (i = 0; i < ab->hw_params->num_rxdma_dst_ring; i++) { 405962306a36Sopenharmony_ci ring_id = dp->rxdma_err_dst_ring[i].ring_id; 406062306a36Sopenharmony_ci ret = ath12k_dp_tx_htt_srng_setup(ab, ring_id, 406162306a36Sopenharmony_ci i, HAL_RXDMA_DST); 406262306a36Sopenharmony_ci if (ret) { 406362306a36Sopenharmony_ci ath12k_warn(ab, "failed to configure rxdma_err_dest_ring%d %d\n", 406462306a36Sopenharmony_ci i, ret); 406562306a36Sopenharmony_ci return ret; 406662306a36Sopenharmony_ci } 406762306a36Sopenharmony_ci } 406862306a36Sopenharmony_ci 406962306a36Sopenharmony_ci if (ab->hw_params->rxdma1_enable) { 407062306a36Sopenharmony_ci ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id; 407162306a36Sopenharmony_ci ret = ath12k_dp_tx_htt_srng_setup(ab, ring_id, 407262306a36Sopenharmony_ci 0, HAL_RXDMA_MONITOR_BUF); 407362306a36Sopenharmony_ci if (ret) { 407462306a36Sopenharmony_ci ath12k_warn(ab, "failed to configure rxdma_mon_buf_ring %d\n", 407562306a36Sopenharmony_ci ret); 407662306a36Sopenharmony_ci return ret; 407762306a36Sopenharmony_ci } 407862306a36Sopenharmony_ci 407962306a36Sopenharmony_ci ring_id = dp->tx_mon_buf_ring.refill_buf_ring.ring_id; 408062306a36Sopenharmony_ci ret = ath12k_dp_tx_htt_srng_setup(ab, ring_id, 408162306a36Sopenharmony_ci 0, HAL_TX_MONITOR_BUF); 408262306a36Sopenharmony_ci if (ret) { 408362306a36Sopenharmony_ci ath12k_warn(ab, "failed to configure rxdma_mon_buf_ring %d\n", 408462306a36Sopenharmony_ci ret); 408562306a36Sopenharmony_ci return ret; 408662306a36Sopenharmony_ci } 408762306a36Sopenharmony_ci } 408862306a36Sopenharmony_ci 408962306a36Sopenharmony_ci ret = ab->hw_params->hw_ops->rxdma_ring_sel_config(ab); 409062306a36Sopenharmony_ci if (ret) { 409162306a36Sopenharmony_ci ath12k_warn(ab, "failed to setup rxdma ring selection config\n"); 409262306a36Sopenharmony_ci return ret; 409362306a36Sopenharmony_ci } 409462306a36Sopenharmony_ci 409562306a36Sopenharmony_ci return 0; 409662306a36Sopenharmony_ci} 409762306a36Sopenharmony_ci 409862306a36Sopenharmony_ciint ath12k_dp_rx_alloc(struct ath12k_base *ab) 409962306a36Sopenharmony_ci{ 410062306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 410162306a36Sopenharmony_ci int i, ret; 410262306a36Sopenharmony_ci 410362306a36Sopenharmony_ci idr_init(&dp->rx_refill_buf_ring.bufs_idr); 410462306a36Sopenharmony_ci spin_lock_init(&dp->rx_refill_buf_ring.idr_lock); 410562306a36Sopenharmony_ci 410662306a36Sopenharmony_ci idr_init(&dp->rxdma_mon_buf_ring.bufs_idr); 410762306a36Sopenharmony_ci spin_lock_init(&dp->rxdma_mon_buf_ring.idr_lock); 410862306a36Sopenharmony_ci 410962306a36Sopenharmony_ci idr_init(&dp->tx_mon_buf_ring.bufs_idr); 411062306a36Sopenharmony_ci spin_lock_init(&dp->tx_mon_buf_ring.idr_lock); 411162306a36Sopenharmony_ci 411262306a36Sopenharmony_ci ret = ath12k_dp_srng_setup(ab, 411362306a36Sopenharmony_ci &dp->rx_refill_buf_ring.refill_buf_ring, 411462306a36Sopenharmony_ci HAL_RXDMA_BUF, 0, 0, 411562306a36Sopenharmony_ci DP_RXDMA_BUF_RING_SIZE); 411662306a36Sopenharmony_ci if (ret) { 411762306a36Sopenharmony_ci ath12k_warn(ab, "failed to setup rx_refill_buf_ring\n"); 411862306a36Sopenharmony_ci return ret; 411962306a36Sopenharmony_ci } 412062306a36Sopenharmony_ci 412162306a36Sopenharmony_ci if (ab->hw_params->rx_mac_buf_ring) { 412262306a36Sopenharmony_ci for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) { 412362306a36Sopenharmony_ci ret = ath12k_dp_srng_setup(ab, 412462306a36Sopenharmony_ci &dp->rx_mac_buf_ring[i], 412562306a36Sopenharmony_ci HAL_RXDMA_BUF, 1, 412662306a36Sopenharmony_ci i, 1024); 412762306a36Sopenharmony_ci if (ret) { 412862306a36Sopenharmony_ci ath12k_warn(ab, "failed to setup rx_mac_buf_ring %d\n", 412962306a36Sopenharmony_ci i); 413062306a36Sopenharmony_ci return ret; 413162306a36Sopenharmony_ci } 413262306a36Sopenharmony_ci } 413362306a36Sopenharmony_ci } 413462306a36Sopenharmony_ci 413562306a36Sopenharmony_ci for (i = 0; i < ab->hw_params->num_rxdma_dst_ring; i++) { 413662306a36Sopenharmony_ci ret = ath12k_dp_srng_setup(ab, &dp->rxdma_err_dst_ring[i], 413762306a36Sopenharmony_ci HAL_RXDMA_DST, 0, i, 413862306a36Sopenharmony_ci DP_RXDMA_ERR_DST_RING_SIZE); 413962306a36Sopenharmony_ci if (ret) { 414062306a36Sopenharmony_ci ath12k_warn(ab, "failed to setup rxdma_err_dst_ring %d\n", i); 414162306a36Sopenharmony_ci return ret; 414262306a36Sopenharmony_ci } 414362306a36Sopenharmony_ci } 414462306a36Sopenharmony_ci 414562306a36Sopenharmony_ci if (ab->hw_params->rxdma1_enable) { 414662306a36Sopenharmony_ci ret = ath12k_dp_srng_setup(ab, 414762306a36Sopenharmony_ci &dp->rxdma_mon_buf_ring.refill_buf_ring, 414862306a36Sopenharmony_ci HAL_RXDMA_MONITOR_BUF, 0, 0, 414962306a36Sopenharmony_ci DP_RXDMA_MONITOR_BUF_RING_SIZE); 415062306a36Sopenharmony_ci if (ret) { 415162306a36Sopenharmony_ci ath12k_warn(ab, "failed to setup HAL_RXDMA_MONITOR_BUF\n"); 415262306a36Sopenharmony_ci return ret; 415362306a36Sopenharmony_ci } 415462306a36Sopenharmony_ci 415562306a36Sopenharmony_ci ret = ath12k_dp_srng_setup(ab, 415662306a36Sopenharmony_ci &dp->tx_mon_buf_ring.refill_buf_ring, 415762306a36Sopenharmony_ci HAL_TX_MONITOR_BUF, 0, 0, 415862306a36Sopenharmony_ci DP_TX_MONITOR_BUF_RING_SIZE); 415962306a36Sopenharmony_ci if (ret) { 416062306a36Sopenharmony_ci ath12k_warn(ab, "failed to setup DP_TX_MONITOR_BUF_RING_SIZE\n"); 416162306a36Sopenharmony_ci return ret; 416262306a36Sopenharmony_ci } 416362306a36Sopenharmony_ci } 416462306a36Sopenharmony_ci 416562306a36Sopenharmony_ci ret = ath12k_dp_rxdma_buf_setup(ab); 416662306a36Sopenharmony_ci if (ret) { 416762306a36Sopenharmony_ci ath12k_warn(ab, "failed to setup rxdma ring\n"); 416862306a36Sopenharmony_ci return ret; 416962306a36Sopenharmony_ci } 417062306a36Sopenharmony_ci 417162306a36Sopenharmony_ci return 0; 417262306a36Sopenharmony_ci} 417362306a36Sopenharmony_ci 417462306a36Sopenharmony_ciint ath12k_dp_rx_pdev_alloc(struct ath12k_base *ab, int mac_id) 417562306a36Sopenharmony_ci{ 417662306a36Sopenharmony_ci struct ath12k *ar = ab->pdevs[mac_id].ar; 417762306a36Sopenharmony_ci struct ath12k_pdev_dp *dp = &ar->dp; 417862306a36Sopenharmony_ci u32 ring_id; 417962306a36Sopenharmony_ci int i; 418062306a36Sopenharmony_ci int ret; 418162306a36Sopenharmony_ci 418262306a36Sopenharmony_ci if (!ab->hw_params->rxdma1_enable) 418362306a36Sopenharmony_ci goto out; 418462306a36Sopenharmony_ci 418562306a36Sopenharmony_ci ret = ath12k_dp_rx_pdev_srng_alloc(ar); 418662306a36Sopenharmony_ci if (ret) { 418762306a36Sopenharmony_ci ath12k_warn(ab, "failed to setup rx srngs\n"); 418862306a36Sopenharmony_ci return ret; 418962306a36Sopenharmony_ci } 419062306a36Sopenharmony_ci 419162306a36Sopenharmony_ci for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) { 419262306a36Sopenharmony_ci ring_id = dp->rxdma_mon_dst_ring[i].ring_id; 419362306a36Sopenharmony_ci ret = ath12k_dp_tx_htt_srng_setup(ab, ring_id, 419462306a36Sopenharmony_ci mac_id + i, 419562306a36Sopenharmony_ci HAL_RXDMA_MONITOR_DST); 419662306a36Sopenharmony_ci if (ret) { 419762306a36Sopenharmony_ci ath12k_warn(ab, 419862306a36Sopenharmony_ci "failed to configure rxdma_mon_dst_ring %d %d\n", 419962306a36Sopenharmony_ci i, ret); 420062306a36Sopenharmony_ci return ret; 420162306a36Sopenharmony_ci } 420262306a36Sopenharmony_ci 420362306a36Sopenharmony_ci ring_id = dp->tx_mon_dst_ring[i].ring_id; 420462306a36Sopenharmony_ci ret = ath12k_dp_tx_htt_srng_setup(ab, ring_id, 420562306a36Sopenharmony_ci mac_id + i, 420662306a36Sopenharmony_ci HAL_TX_MONITOR_DST); 420762306a36Sopenharmony_ci if (ret) { 420862306a36Sopenharmony_ci ath12k_warn(ab, 420962306a36Sopenharmony_ci "failed to configure tx_mon_dst_ring %d %d\n", 421062306a36Sopenharmony_ci i, ret); 421162306a36Sopenharmony_ci return ret; 421262306a36Sopenharmony_ci } 421362306a36Sopenharmony_ci } 421462306a36Sopenharmony_ciout: 421562306a36Sopenharmony_ci return 0; 421662306a36Sopenharmony_ci} 421762306a36Sopenharmony_ci 421862306a36Sopenharmony_cistatic int ath12k_dp_rx_pdev_mon_status_attach(struct ath12k *ar) 421962306a36Sopenharmony_ci{ 422062306a36Sopenharmony_ci struct ath12k_pdev_dp *dp = &ar->dp; 422162306a36Sopenharmony_ci struct ath12k_mon_data *pmon = (struct ath12k_mon_data *)&dp->mon_data; 422262306a36Sopenharmony_ci 422362306a36Sopenharmony_ci skb_queue_head_init(&pmon->rx_status_q); 422462306a36Sopenharmony_ci 422562306a36Sopenharmony_ci pmon->mon_ppdu_status = DP_PPDU_STATUS_START; 422662306a36Sopenharmony_ci 422762306a36Sopenharmony_ci memset(&pmon->rx_mon_stats, 0, 422862306a36Sopenharmony_ci sizeof(pmon->rx_mon_stats)); 422962306a36Sopenharmony_ci return 0; 423062306a36Sopenharmony_ci} 423162306a36Sopenharmony_ci 423262306a36Sopenharmony_ciint ath12k_dp_rx_pdev_mon_attach(struct ath12k *ar) 423362306a36Sopenharmony_ci{ 423462306a36Sopenharmony_ci struct ath12k_pdev_dp *dp = &ar->dp; 423562306a36Sopenharmony_ci struct ath12k_mon_data *pmon = &dp->mon_data; 423662306a36Sopenharmony_ci int ret = 0; 423762306a36Sopenharmony_ci 423862306a36Sopenharmony_ci ret = ath12k_dp_rx_pdev_mon_status_attach(ar); 423962306a36Sopenharmony_ci if (ret) { 424062306a36Sopenharmony_ci ath12k_warn(ar->ab, "pdev_mon_status_attach() failed"); 424162306a36Sopenharmony_ci return ret; 424262306a36Sopenharmony_ci } 424362306a36Sopenharmony_ci 424462306a36Sopenharmony_ci /* if rxdma1_enable is false, no need to setup 424562306a36Sopenharmony_ci * rxdma_mon_desc_ring. 424662306a36Sopenharmony_ci */ 424762306a36Sopenharmony_ci if (!ar->ab->hw_params->rxdma1_enable) 424862306a36Sopenharmony_ci return 0; 424962306a36Sopenharmony_ci 425062306a36Sopenharmony_ci pmon->mon_last_linkdesc_paddr = 0; 425162306a36Sopenharmony_ci pmon->mon_last_buf_cookie = DP_RX_DESC_COOKIE_MAX + 1; 425262306a36Sopenharmony_ci spin_lock_init(&pmon->mon_lock); 425362306a36Sopenharmony_ci 425462306a36Sopenharmony_ci return 0; 425562306a36Sopenharmony_ci} 425662306a36Sopenharmony_ci 425762306a36Sopenharmony_ciint ath12k_dp_rx_pktlog_start(struct ath12k_base *ab) 425862306a36Sopenharmony_ci{ 425962306a36Sopenharmony_ci /* start reap timer */ 426062306a36Sopenharmony_ci mod_timer(&ab->mon_reap_timer, 426162306a36Sopenharmony_ci jiffies + msecs_to_jiffies(ATH12K_MON_TIMER_INTERVAL)); 426262306a36Sopenharmony_ci 426362306a36Sopenharmony_ci return 0; 426462306a36Sopenharmony_ci} 426562306a36Sopenharmony_ci 426662306a36Sopenharmony_ciint ath12k_dp_rx_pktlog_stop(struct ath12k_base *ab, bool stop_timer) 426762306a36Sopenharmony_ci{ 426862306a36Sopenharmony_ci int ret; 426962306a36Sopenharmony_ci 427062306a36Sopenharmony_ci if (stop_timer) 427162306a36Sopenharmony_ci del_timer_sync(&ab->mon_reap_timer); 427262306a36Sopenharmony_ci 427362306a36Sopenharmony_ci /* reap all the monitor related rings */ 427462306a36Sopenharmony_ci ret = ath12k_dp_purge_mon_ring(ab); 427562306a36Sopenharmony_ci if (ret) { 427662306a36Sopenharmony_ci ath12k_warn(ab, "failed to purge dp mon ring: %d\n", ret); 427762306a36Sopenharmony_ci return ret; 427862306a36Sopenharmony_ci } 427962306a36Sopenharmony_ci 428062306a36Sopenharmony_ci return 0; 428162306a36Sopenharmony_ci} 4282