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