wifi: ath12k: Move regular msdu processing functions to wifi7 directory

Move arch specific RX MSDU processing related functions to wifi7 directory.

The moved APIs will be a part of dp_rx.c file inside wifi7 directory.
wifi7/dp_rx.c file will continue to be part of ath12k.ko temporarily
until the corresponding infra for movement to ath12k_wifi7.ko arrives
in upcoming patches.

Architecture specific APIs:
ath12k_dp_rx_msdu_coalesce
ath12k_dp_rx_h_csum_offload
ath12k_dp_rx_h_mpdu
ath12k_dp_rx_process
ath12k_dp_rx_process_received_packets
ath12k_dp_rx_h_verify_tkip_mic
ath12k_dp_rx_process_msdu

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

Signed-off-by: Pavankumar Nandeshwar <quic_pnandesh@quicinc.com>
Signed-off-by: Ripan Deuri <quic_rdeuri@quicinc.com>
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Link: https://patch.msgid.link/20250828173553.3341351-11-quic_rdeuri@quicinc.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
This commit is contained in:
Pavankumar Nandeshwar 2025-08-28 23:05:43 +05:30 committed by Jeff Johnson
parent 6b4954d3f0
commit a7cfbb18d4
4 changed files with 547 additions and 544 deletions

View File

@ -1664,95 +1664,8 @@ void ath12k_dp_htt_htc_t2h_msg_handler(struct ath12k_base *ab,
}
EXPORT_SYMBOL(ath12k_dp_htt_htc_t2h_msg_handler);
static int ath12k_dp_rx_msdu_coalesce(struct ath12k *ar,
struct sk_buff_head *msdu_list,
struct sk_buff *first, struct sk_buff *last,
u8 l3pad_bytes, int msdu_len)
{
struct ath12k_base *ab = ar->ab;
struct sk_buff *skb;
struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(first);
int buf_first_hdr_len, buf_first_len;
struct hal_rx_desc *ldesc;
int space_extra, rem_len, buf_len;
u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz;
bool is_continuation;
/* As the msdu is spread across multiple rx buffers,
* find the offset to the start of msdu for computing
* the length of the msdu in the first buffer.
*/
buf_first_hdr_len = hal_rx_desc_sz + l3pad_bytes;
buf_first_len = DP_RX_BUFFER_SIZE - buf_first_hdr_len;
if (WARN_ON_ONCE(msdu_len <= buf_first_len)) {
skb_put(first, buf_first_hdr_len + msdu_len);
skb_pull(first, buf_first_hdr_len);
return 0;
}
ldesc = (struct hal_rx_desc *)last->data;
rxcb->is_first_msdu = ath12k_dp_rx_h_first_msdu(ab, ldesc);
rxcb->is_last_msdu = ath12k_dp_rx_h_last_msdu(ab, ldesc);
/* MSDU spans over multiple buffers because the length of the MSDU
* exceeds DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE. So assume the data
* in the first buf is of length DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE.
*/
skb_put(first, DP_RX_BUFFER_SIZE);
skb_pull(first, buf_first_hdr_len);
/* When an MSDU spread over multiple buffers MSDU_END
* tlvs are valid only in the last buffer. Copy those tlvs.
*/
ath12k_dp_rx_desc_end_tlv_copy(ab, rxcb->rx_desc, ldesc);
space_extra = msdu_len - (buf_first_len + skb_tailroom(first));
if (space_extra > 0 &&
(pskb_expand_head(first, 0, space_extra, GFP_ATOMIC) < 0)) {
/* Free up all buffers of the MSDU */
while ((skb = __skb_dequeue(msdu_list)) != NULL) {
rxcb = ATH12K_SKB_RXCB(skb);
if (!rxcb->is_continuation) {
dev_kfree_skb_any(skb);
break;
}
dev_kfree_skb_any(skb);
}
return -ENOMEM;
}
rem_len = msdu_len - buf_first_len;
while ((skb = __skb_dequeue(msdu_list)) != NULL && rem_len > 0) {
rxcb = ATH12K_SKB_RXCB(skb);
is_continuation = rxcb->is_continuation;
if (is_continuation)
buf_len = DP_RX_BUFFER_SIZE - hal_rx_desc_sz;
else
buf_len = rem_len;
if (buf_len > (DP_RX_BUFFER_SIZE - hal_rx_desc_sz)) {
WARN_ON_ONCE(1);
dev_kfree_skb_any(skb);
return -EINVAL;
}
skb_put(skb, buf_len + hal_rx_desc_sz);
skb_pull(skb, hal_rx_desc_sz);
skb_copy_from_linear_data(skb, skb_put(first, buf_len),
buf_len);
dev_kfree_skb_any(skb);
rem_len -= buf_len;
if (!is_continuation)
break;
}
return 0;
}
static struct sk_buff *ath12k_dp_rx_get_msdu_last_buf(struct sk_buff_head *msdu_list,
struct sk_buff *first)
struct sk_buff *ath12k_dp_rx_get_msdu_last_buf(struct sk_buff_head *msdu_list,
struct sk_buff *first)
{
struct sk_buff *skb;
struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(first);
@ -1769,13 +1682,6 @@ static struct sk_buff *ath12k_dp_rx_get_msdu_last_buf(struct sk_buff_head *msdu_
return NULL;
}
static void ath12k_dp_rx_h_csum_offload(struct sk_buff *msdu,
struct ath12k_dp_rx_info *rx_info)
{
msdu->ip_summed = (rx_info->ip_csum_fail || rx_info->l4_csum_fail) ?
CHECKSUM_NONE : CHECKSUM_UNNECESSARY;
}
int ath12k_dp_rx_crypto_mic_len(struct ath12k *ar, enum hal_encrypt_type enctype)
{
switch (enctype) {
@ -2094,84 +2000,6 @@ ath12k_dp_rx_h_find_peer(struct ath12k_base *ab, struct sk_buff *msdu,
return peer;
}
void ath12k_dp_rx_h_mpdu(struct ath12k *ar,
struct sk_buff *msdu,
struct hal_rx_desc *rx_desc,
struct ath12k_dp_rx_info *rx_info)
{
struct ath12k_base *ab = ar->ab;
struct ath12k_skb_rxcb *rxcb;
enum hal_encrypt_type enctype;
bool is_decrypted = false;
struct ieee80211_hdr *hdr;
struct ath12k_peer *peer;
struct ieee80211_rx_status *rx_status = rx_info->rx_status;
u32 err_bitmap;
/* PN for multicast packets will be checked in mac80211 */
rxcb = ATH12K_SKB_RXCB(msdu);
rxcb->is_mcbc = rx_info->is_mcbc;
if (rxcb->is_mcbc)
rxcb->peer_id = rx_info->peer_id;
spin_lock_bh(&ar->ab->base_lock);
peer = ath12k_dp_rx_h_find_peer(ar->ab, msdu, rx_info);
if (peer) {
/* resetting mcbc bit because mcbc packets are unicast
* packets only for AP as STA sends unicast packets.
*/
rxcb->is_mcbc = rxcb->is_mcbc && !peer->ucast_ra_only;
if (rxcb->is_mcbc)
enctype = peer->sec_type_grp;
else
enctype = peer->sec_type;
} else {
enctype = HAL_ENCRYPT_TYPE_OPEN;
}
spin_unlock_bh(&ar->ab->base_lock);
err_bitmap = ath12k_dp_rx_h_mpdu_err(ab, rx_desc);
if (enctype != HAL_ENCRYPT_TYPE_OPEN && !err_bitmap)
is_decrypted = ath12k_dp_rx_h_is_decrypted(ab, rx_desc);
/* Clear per-MPDU flags while leaving per-PPDU flags intact */
rx_status->flag &= ~(RX_FLAG_FAILED_FCS_CRC |
RX_FLAG_MMIC_ERROR |
RX_FLAG_DECRYPTED |
RX_FLAG_IV_STRIPPED |
RX_FLAG_MMIC_STRIPPED);
if (err_bitmap & HAL_RX_MPDU_ERR_FCS)
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
if (err_bitmap & HAL_RX_MPDU_ERR_TKIP_MIC)
rx_status->flag |= RX_FLAG_MMIC_ERROR;
if (is_decrypted) {
rx_status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_MMIC_STRIPPED;
if (rx_info->is_mcbc)
rx_status->flag |= RX_FLAG_MIC_STRIPPED |
RX_FLAG_ICV_STRIPPED;
else
rx_status->flag |= RX_FLAG_IV_STRIPPED |
RX_FLAG_PN_VALIDATED;
}
ath12k_dp_rx_h_csum_offload(msdu, rx_info);
ath12k_dp_rx_h_undecap(ar, msdu, rx_desc,
enctype, rx_status, is_decrypted);
if (!is_decrypted || rx_info->is_mcbc)
return;
if (rx_info->decap_type != DP_RX_DECAP_TYPE_ETHERNET2_DIX) {
hdr = (void *)msdu->data;
hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED);
}
}
static void ath12k_dp_rx_h_rate(struct ath12k *ar, struct ath12k_dp_rx_info *rx_info)
{
struct ieee80211_supported_band *sband;
@ -2416,140 +2244,9 @@ bool ath12k_dp_rx_check_nwifi_hdr_len_valid(struct ath12k_base *ab,
return false;
}
static int ath12k_dp_rx_process_msdu(struct ath12k *ar,
struct sk_buff *msdu,
struct sk_buff_head *msdu_list,
struct ath12k_dp_rx_info *rx_info)
{
struct ath12k_base *ab = ar->ab;
struct hal_rx_desc *rx_desc, *lrx_desc;
struct ath12k_skb_rxcb *rxcb;
struct sk_buff *last_buf;
u8 l3_pad_bytes;
u16 msdu_len;
int ret;
u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz;
last_buf = ath12k_dp_rx_get_msdu_last_buf(msdu_list, msdu);
if (!last_buf) {
ath12k_warn(ab,
"No valid Rx buffer to access MSDU_END tlv\n");
ret = -EIO;
goto free_out;
}
rx_desc = (struct hal_rx_desc *)msdu->data;
lrx_desc = (struct hal_rx_desc *)last_buf->data;
if (!ath12k_dp_rx_h_msdu_done(ab, lrx_desc)) {
ath12k_warn(ab, "msdu_done bit in msdu_end is not set\n");
ret = -EIO;
goto free_out;
}
rxcb = ATH12K_SKB_RXCB(msdu);
rxcb->rx_desc = rx_desc;
msdu_len = ath12k_dp_rx_h_msdu_len(ab, lrx_desc);
l3_pad_bytes = ath12k_dp_rx_h_l3pad(ab, lrx_desc);
if (rxcb->is_frag) {
skb_pull(msdu, hal_rx_desc_sz);
} else if (!rxcb->is_continuation) {
if ((msdu_len + hal_rx_desc_sz) > DP_RX_BUFFER_SIZE) {
ret = -EINVAL;
ath12k_warn(ab, "invalid msdu len %u\n", msdu_len);
ath12k_dbg_dump(ab, ATH12K_DBG_DATA, NULL, "", rx_desc,
sizeof(*rx_desc));
goto free_out;
}
skb_put(msdu, hal_rx_desc_sz + l3_pad_bytes + msdu_len);
skb_pull(msdu, hal_rx_desc_sz + l3_pad_bytes);
} else {
ret = ath12k_dp_rx_msdu_coalesce(ar, msdu_list,
msdu, last_buf,
l3_pad_bytes, msdu_len);
if (ret) {
ath12k_warn(ab,
"failed to coalesce msdu rx buffer%d\n", ret);
goto free_out;
}
}
if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, rx_desc, msdu))) {
ret = -EINVAL;
goto free_out;
}
ath12k_dp_rx_h_fetch_info(ab, rx_desc, rx_info);
ath12k_dp_rx_h_ppdu(ar, rx_info);
ath12k_dp_rx_h_mpdu(ar, msdu, rx_desc, rx_info);
rx_info->rx_status->flag |= RX_FLAG_SKIP_MONITOR | RX_FLAG_DUP_VALIDATED;
return 0;
free_out:
return ret;
}
static void ath12k_dp_rx_process_received_packets(struct ath12k_base *ab,
struct napi_struct *napi,
struct sk_buff_head *msdu_list,
int ring_id)
{
struct ath12k_hw_group *ag = ab->ag;
struct ieee80211_rx_status rx_status = {};
struct ath12k_skb_rxcb *rxcb;
struct sk_buff *msdu;
struct ath12k *ar;
struct ath12k_hw_link *hw_links = ag->hw_links;
struct ath12k_base *partner_ab;
struct ath12k_dp_rx_info rx_info;
u8 hw_link_id, pdev_id;
int ret;
if (skb_queue_empty(msdu_list))
return;
rx_info.addr2_present = false;
rx_info.rx_status = &rx_status;
rcu_read_lock();
while ((msdu = __skb_dequeue(msdu_list))) {
rxcb = ATH12K_SKB_RXCB(msdu);
hw_link_id = rxcb->hw_link_id;
partner_ab = ath12k_ag_to_ab(ag,
hw_links[hw_link_id].device_id);
pdev_id = ath12k_hw_mac_id_to_pdev_id(partner_ab->hw_params,
hw_links[hw_link_id].pdev_idx);
ar = partner_ab->pdevs[pdev_id].ar;
if (!rcu_dereference(partner_ab->pdevs_active[pdev_id])) {
dev_kfree_skb_any(msdu);
continue;
}
if (test_bit(ATH12K_FLAG_CAC_RUNNING, &ar->dev_flags)) {
dev_kfree_skb_any(msdu);
continue;
}
ret = ath12k_dp_rx_process_msdu(ar, msdu, msdu_list, &rx_info);
if (ret) {
ath12k_dbg(ab, ATH12K_DBG_DATA,
"Unable to process msdu %d", ret);
dev_kfree_skb_any(msdu);
continue;
}
ath12k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_info);
}
rcu_read_unlock();
}
static u16 ath12k_dp_rx_get_peer_id(struct ath12k_base *ab,
enum ath12k_peer_metadata_version ver,
__le32 peer_metadata)
u16 ath12k_dp_rx_get_peer_id(struct ath12k_base *ab,
enum ath12k_peer_metadata_version ver,
__le32 peer_metadata)
{
switch (ver) {
default:
@ -2570,166 +2267,6 @@ static u16 ath12k_dp_rx_get_peer_id(struct ath12k_base *ab,
}
}
int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id,
struct napi_struct *napi, int budget)
{
struct ath12k_hw_group *ag = ab->ag;
struct list_head rx_desc_used_list[ATH12K_MAX_DEVICES];
struct ath12k_hw_link *hw_links = ag->hw_links;
int num_buffs_reaped[ATH12K_MAX_DEVICES] = {};
struct ath12k_rx_desc_info *desc_info;
struct ath12k_dp *dp = &ab->dp;
struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
struct hal_reo_dest_ring *desc;
struct ath12k_base *partner_ab;
struct sk_buff_head msdu_list;
struct ath12k_skb_rxcb *rxcb;
int total_msdu_reaped = 0;
u8 hw_link_id, device_id;
struct hal_srng *srng;
struct sk_buff *msdu;
bool done = false;
u64 desc_va;
__skb_queue_head_init(&msdu_list);
for (device_id = 0; device_id < ATH12K_MAX_DEVICES; device_id++)
INIT_LIST_HEAD(&rx_desc_used_list[device_id]);
srng = &ab->hal.srng_list[dp->reo_dst_ring[ring_id].ring_id];
spin_lock_bh(&srng->lock);
try_again:
ath12k_hal_srng_access_begin(ab, srng);
while ((desc = ath12k_hal_srng_dst_get_next_entry(ab, srng))) {
struct rx_mpdu_desc *mpdu_info;
struct rx_msdu_desc *msdu_info;
enum hal_reo_dest_ring_push_reason push_reason;
u32 cookie;
cookie = le32_get_bits(desc->buf_addr_info.info1,
BUFFER_ADDR_INFO1_SW_COOKIE);
hw_link_id = le32_get_bits(desc->info0,
HAL_REO_DEST_RING_INFO0_SRC_LINK_ID);
desc_va = ((u64)le32_to_cpu(desc->buf_va_hi) << 32 |
le32_to_cpu(desc->buf_va_lo));
desc_info = (struct ath12k_rx_desc_info *)((unsigned long)desc_va);
device_id = hw_links[hw_link_id].device_id;
partner_ab = ath12k_ag_to_ab(ag, device_id);
if (unlikely(!partner_ab)) {
if (desc_info->skb) {
dev_kfree_skb_any(desc_info->skb);
desc_info->skb = NULL;
}
continue;
}
/* retry manual desc retrieval */
if (!desc_info) {
desc_info = ath12k_dp_get_rx_desc(partner_ab, cookie);
if (!desc_info) {
ath12k_warn(partner_ab, "Invalid cookie in manual descriptor retrieval: 0x%x\n",
cookie);
continue;
}
}
if (desc_info->magic != ATH12K_DP_RX_DESC_MAGIC)
ath12k_warn(ab, "Check HW CC implementation");
msdu = desc_info->skb;
desc_info->skb = NULL;
list_add_tail(&desc_info->list, &rx_desc_used_list[device_id]);
rxcb = ATH12K_SKB_RXCB(msdu);
dma_unmap_single(partner_ab->dev, rxcb->paddr,
msdu->len + skb_tailroom(msdu),
DMA_FROM_DEVICE);
num_buffs_reaped[device_id]++;
ab->device_stats.reo_rx[ring_id][ab->device_id]++;
push_reason = le32_get_bits(desc->info0,
HAL_REO_DEST_RING_INFO0_PUSH_REASON);
if (push_reason !=
HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) {
dev_kfree_skb_any(msdu);
ab->device_stats.hal_reo_error[ring_id]++;
continue;
}
msdu_info = &desc->rx_msdu_info;
mpdu_info = &desc->rx_mpdu_info;
rxcb->is_first_msdu = !!(le32_to_cpu(msdu_info->info0) &
RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU);
rxcb->is_last_msdu = !!(le32_to_cpu(msdu_info->info0) &
RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU);
rxcb->is_continuation = !!(le32_to_cpu(msdu_info->info0) &
RX_MSDU_DESC_INFO0_MSDU_CONTINUATION);
rxcb->hw_link_id = hw_link_id;
rxcb->peer_id = ath12k_dp_rx_get_peer_id(ab, dp->peer_metadata_ver,
mpdu_info->peer_meta_data);
rxcb->tid = le32_get_bits(mpdu_info->info0,
RX_MPDU_DESC_INFO0_TID);
__skb_queue_tail(&msdu_list, msdu);
if (!rxcb->is_continuation) {
total_msdu_reaped++;
done = true;
} else {
done = false;
}
if (total_msdu_reaped >= budget)
break;
}
/* Hw might have updated the head pointer after we cached it.
* In this case, even though there are entries in the ring we'll
* get rx_desc NULL. Give the read another try with updated cached
* head pointer so that we can reap complete MPDU in the current
* rx processing.
*/
if (!done && ath12k_hal_srng_dst_num_free(ab, srng, true)) {
ath12k_hal_srng_access_end(ab, srng);
goto try_again;
}
ath12k_hal_srng_access_end(ab, srng);
spin_unlock_bh(&srng->lock);
if (!total_msdu_reaped)
goto exit;
for (device_id = 0; device_id < ATH12K_MAX_DEVICES; device_id++) {
if (!num_buffs_reaped[device_id])
continue;
partner_ab = ath12k_ag_to_ab(ag, device_id);
rx_ring = &partner_ab->dp.rx_refill_buf_ring;
ath12k_dp_rx_bufs_replenish(partner_ab, rx_ring,
&rx_desc_used_list[device_id],
num_buffs_reaped[device_id]);
}
ath12k_dp_rx_process_received_packets(ab, napi, &msdu_list,
ring_id);
exit:
return total_msdu_reaped;
}
static void ath12k_dp_rx_frag_timer(struct timer_list *timer)
{
struct ath12k_dp_rx_tid *rx_tid = timer_container_of(rx_tid, timer,
@ -2787,9 +2324,9 @@ int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, const u8 *peer_mac, int vdev
return 0;
}
static int ath12k_dp_rx_h_michael_mic(struct crypto_shash *tfm, u8 *key,
struct ieee80211_hdr *hdr, u8 *data,
size_t data_len, u8 *mic)
int ath12k_dp_rx_h_michael_mic(struct crypto_shash *tfm, u8 *key,
struct ieee80211_hdr *hdr, u8 *data,
size_t data_len, u8 *mic)
{
SHASH_DESC_ON_STACK(desc, tfm);
u8 mic_hdr[16] = {};
@ -2828,70 +2365,6 @@ static int ath12k_dp_rx_h_michael_mic(struct crypto_shash *tfm, u8 *key,
return ret;
}
int ath12k_dp_rx_h_verify_tkip_mic(struct ath12k *ar, struct ath12k_peer *peer,
struct sk_buff *msdu)
{
struct ath12k_base *ab = ar->ab;
struct hal_rx_desc *rx_desc = (struct hal_rx_desc *)msdu->data;
struct ieee80211_rx_status *rxs = IEEE80211_SKB_RXCB(msdu);
struct ieee80211_key_conf *key_conf;
struct ieee80211_hdr *hdr;
struct ath12k_dp_rx_info rx_info;
u8 mic[IEEE80211_CCMP_MIC_LEN];
int head_len, tail_len, ret;
size_t data_len;
u32 hdr_len, hal_rx_desc_sz = ar->ab->hal.hal_desc_sz;
u8 *key, *data;
u8 key_idx;
if (ath12k_dp_rx_h_enctype(ab, rx_desc) != HAL_ENCRYPT_TYPE_TKIP_MIC)
return 0;
rx_info.addr2_present = false;
rx_info.rx_status = rxs;
hdr = (struct ieee80211_hdr *)(msdu->data + hal_rx_desc_sz);
hdr_len = ieee80211_hdrlen(hdr->frame_control);
head_len = hdr_len + hal_rx_desc_sz + IEEE80211_TKIP_IV_LEN;
tail_len = IEEE80211_CCMP_MIC_LEN + IEEE80211_TKIP_ICV_LEN + FCS_LEN;
if (!is_multicast_ether_addr(hdr->addr1))
key_idx = peer->ucast_keyidx;
else
key_idx = peer->mcast_keyidx;
key_conf = peer->keys[key_idx];
data = msdu->data + head_len;
data_len = msdu->len - head_len - tail_len;
key = &key_conf->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY];
ret = ath12k_dp_rx_h_michael_mic(peer->tfm_mmic, key, hdr, data, data_len, mic);
if (ret || memcmp(mic, data + data_len, IEEE80211_CCMP_MIC_LEN))
goto mic_fail;
return 0;
mic_fail:
(ATH12K_SKB_RXCB(msdu))->is_first_msdu = true;
(ATH12K_SKB_RXCB(msdu))->is_last_msdu = true;
ath12k_dp_rx_h_fetch_info(ab, rx_desc, &rx_info);
rxs->flag |= RX_FLAG_MMIC_ERROR | RX_FLAG_MMIC_STRIPPED |
RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED;
skb_pull(msdu, hal_rx_desc_sz);
if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, rx_desc, msdu)))
return -EINVAL;
ath12k_dp_rx_h_ppdu(ar, &rx_info);
ath12k_dp_rx_h_undecap(ar, msdu, rx_desc,
HAL_ENCRYPT_TYPE_TKIP_MIC, rxs, true);
ieee80211_rx(ath12k_ar_to_hw(ar), msdu);
return -EINVAL;
}
void ath12k_dp_rx_h_undecap_frag(struct ath12k *ar, struct sk_buff *msdu,
enum hal_encrypt_type enctype, u32 flags)
{

View File

@ -6,6 +6,7 @@
#ifndef ATH12K_DP_RX_H
#define ATH12K_DP_RX_H
#include <crypto/hash.h>
#include "core.h"
#include "wifi7/hal_rx_desc.h"
#include "debug.h"
@ -353,20 +354,20 @@ void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *napi,
bool ath12k_dp_rx_check_nwifi_hdr_len_valid(struct ath12k_base *ab,
struct hal_rx_desc *rx_desc,
struct sk_buff *msdu);
void ath12k_dp_rx_h_mpdu(struct ath12k *ar,
struct sk_buff *msdu,
struct hal_rx_desc *rx_desc,
struct ath12k_dp_rx_info *rx_info);
u64 ath12k_dp_rx_h_get_pn(struct ath12k *ar, struct sk_buff *skb);
void ath12k_dp_rx_h_sort_frags(struct ath12k_base *ab,
struct sk_buff_head *frag_list,
struct sk_buff *cur_frag);
void ath12k_dp_rx_h_undecap_frag(struct ath12k *ar, struct sk_buff *msdu,
enum hal_encrypt_type enctype, u32 flags);
int ath12k_dp_rx_h_verify_tkip_mic(struct ath12k *ar, struct ath12k_peer *peer,
struct sk_buff *msdu);
void ath12k_dp_rx_frags_cleanup(struct ath12k_dp_rx_tid *rx_tid,
bool rel_link_desc);
int ath12k_dp_rx_h_michael_mic(struct crypto_shash *tfm, u8 *key,
struct ieee80211_hdr *hdr, u8 *data,
size_t data_len, u8 *mic);
u16 ath12k_dp_rx_get_peer_id(struct ath12k_base *ab,
enum ath12k_peer_metadata_version ver,
__le32 peer_metadata);
int ath12k_dp_rx_ampdu_start(struct ath12k *ar,
struct ieee80211_ampdu_params *params,
u8 link_id);
@ -394,9 +395,6 @@ int ath12k_dp_rx_pdev_alloc(struct ath12k_base *ab, int pdev_idx);
void ath12k_dp_rx_pdev_free(struct ath12k_base *ab, int pdev_idx);
void ath12k_dp_rx_reo_cmd_list_cleanup(struct ath12k_base *ab);
void ath12k_dp_rx_process_reo_status(struct ath12k_base *ab);
int ath12k_dp_rx_process(struct ath12k_base *ab, int mac_id,
struct napi_struct *napi,
int budget);
int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab,
struct dp_rxdma_ring *rx_ring,
struct list_head *used_list,
@ -431,4 +429,6 @@ int ath12k_dp_rx_link_desc_return(struct ath12k_base *ab,
bool ath12k_dp_rxdesc_mpdu_valid(struct ath12k_base *ab,
struct hal_rx_desc *rx_desc);
void ath12k_dp_rx_h_ppdu(struct ath12k *ar, struct ath12k_dp_rx_info *rx_info);
struct sk_buff *ath12k_dp_rx_get_msdu_last_buf(struct sk_buff_head *msdu_list,
struct sk_buff *first);
#endif /* ATH12K_DP_RX_H */

View File

@ -8,6 +8,469 @@
#include "../dp_tx.h"
#include "../peer.h"
static void ath12k_dp_rx_h_csum_offload(struct sk_buff *msdu,
struct ath12k_dp_rx_info *rx_info)
{
msdu->ip_summed = (rx_info->ip_csum_fail || rx_info->l4_csum_fail) ?
CHECKSUM_NONE : CHECKSUM_UNNECESSARY;
}
static void ath12k_dp_rx_h_mpdu(struct ath12k *ar,
struct sk_buff *msdu,
struct hal_rx_desc *rx_desc,
struct ath12k_dp_rx_info *rx_info)
{
struct ath12k_base *ab = ar->ab;
struct ath12k_skb_rxcb *rxcb;
enum hal_encrypt_type enctype;
bool is_decrypted = false;
struct ieee80211_hdr *hdr;
struct ath12k_peer *peer;
struct ieee80211_rx_status *rx_status = rx_info->rx_status;
u32 err_bitmap;
/* PN for multicast packets will be checked in mac80211 */
rxcb = ATH12K_SKB_RXCB(msdu);
rxcb->is_mcbc = rx_info->is_mcbc;
if (rxcb->is_mcbc)
rxcb->peer_id = rx_info->peer_id;
spin_lock_bh(&ar->ab->base_lock);
peer = ath12k_dp_rx_h_find_peer(ar->ab, msdu, rx_info);
if (peer) {
/* resetting mcbc bit because mcbc packets are unicast
* packets only for AP as STA sends unicast packets.
*/
rxcb->is_mcbc = rxcb->is_mcbc && !peer->ucast_ra_only;
if (rxcb->is_mcbc)
enctype = peer->sec_type_grp;
else
enctype = peer->sec_type;
} else {
enctype = HAL_ENCRYPT_TYPE_OPEN;
}
spin_unlock_bh(&ar->ab->base_lock);
err_bitmap = ath12k_dp_rx_h_mpdu_err(ab, rx_desc);
if (enctype != HAL_ENCRYPT_TYPE_OPEN && !err_bitmap)
is_decrypted = ath12k_dp_rx_h_is_decrypted(ab, rx_desc);
/* Clear per-MPDU flags while leaving per-PPDU flags intact */
rx_status->flag &= ~(RX_FLAG_FAILED_FCS_CRC |
RX_FLAG_MMIC_ERROR |
RX_FLAG_DECRYPTED |
RX_FLAG_IV_STRIPPED |
RX_FLAG_MMIC_STRIPPED);
if (err_bitmap & HAL_RX_MPDU_ERR_FCS)
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
if (err_bitmap & HAL_RX_MPDU_ERR_TKIP_MIC)
rx_status->flag |= RX_FLAG_MMIC_ERROR;
if (is_decrypted) {
rx_status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_MMIC_STRIPPED;
if (rx_info->is_mcbc)
rx_status->flag |= RX_FLAG_MIC_STRIPPED |
RX_FLAG_ICV_STRIPPED;
else
rx_status->flag |= RX_FLAG_IV_STRIPPED |
RX_FLAG_PN_VALIDATED;
}
ath12k_dp_rx_h_csum_offload(msdu, rx_info);
ath12k_dp_rx_h_undecap(ar, msdu, rx_desc,
enctype, rx_status, is_decrypted);
if (!is_decrypted || rx_info->is_mcbc)
return;
if (rx_info->decap_type != DP_RX_DECAP_TYPE_ETHERNET2_DIX) {
hdr = (void *)msdu->data;
hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED);
}
}
static int ath12k_dp_rx_msdu_coalesce(struct ath12k *ar,
struct sk_buff_head *msdu_list,
struct sk_buff *first, struct sk_buff *last,
u8 l3pad_bytes, int msdu_len)
{
struct ath12k_base *ab = ar->ab;
struct sk_buff *skb;
struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(first);
int buf_first_hdr_len, buf_first_len;
struct hal_rx_desc *ldesc;
int space_extra, rem_len, buf_len;
u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz;
bool is_continuation;
/* As the msdu is spread across multiple rx buffers,
* find the offset to the start of msdu for computing
* the length of the msdu in the first buffer.
*/
buf_first_hdr_len = hal_rx_desc_sz + l3pad_bytes;
buf_first_len = DP_RX_BUFFER_SIZE - buf_first_hdr_len;
if (WARN_ON_ONCE(msdu_len <= buf_first_len)) {
skb_put(first, buf_first_hdr_len + msdu_len);
skb_pull(first, buf_first_hdr_len);
return 0;
}
ldesc = (struct hal_rx_desc *)last->data;
rxcb->is_first_msdu = ath12k_dp_rx_h_first_msdu(ab, ldesc);
rxcb->is_last_msdu = ath12k_dp_rx_h_last_msdu(ab, ldesc);
/* MSDU spans over multiple buffers because the length of the MSDU
* exceeds DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE. So assume the data
* in the first buf is of length DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE.
*/
skb_put(first, DP_RX_BUFFER_SIZE);
skb_pull(first, buf_first_hdr_len);
/* When an MSDU spread over multiple buffers MSDU_END
* tlvs are valid only in the last buffer. Copy those tlvs.
*/
ath12k_dp_rx_desc_end_tlv_copy(ab, rxcb->rx_desc, ldesc);
space_extra = msdu_len - (buf_first_len + skb_tailroom(first));
if (space_extra > 0 &&
(pskb_expand_head(first, 0, space_extra, GFP_ATOMIC) < 0)) {
/* Free up all buffers of the MSDU */
while ((skb = __skb_dequeue(msdu_list)) != NULL) {
rxcb = ATH12K_SKB_RXCB(skb);
if (!rxcb->is_continuation) {
dev_kfree_skb_any(skb);
break;
}
dev_kfree_skb_any(skb);
}
return -ENOMEM;
}
rem_len = msdu_len - buf_first_len;
while ((skb = __skb_dequeue(msdu_list)) != NULL && rem_len > 0) {
rxcb = ATH12K_SKB_RXCB(skb);
is_continuation = rxcb->is_continuation;
if (is_continuation)
buf_len = DP_RX_BUFFER_SIZE - hal_rx_desc_sz;
else
buf_len = rem_len;
if (buf_len > (DP_RX_BUFFER_SIZE - hal_rx_desc_sz)) {
WARN_ON_ONCE(1);
dev_kfree_skb_any(skb);
return -EINVAL;
}
skb_put(skb, buf_len + hal_rx_desc_sz);
skb_pull(skb, hal_rx_desc_sz);
skb_copy_from_linear_data(skb, skb_put(first, buf_len),
buf_len);
dev_kfree_skb_any(skb);
rem_len -= buf_len;
if (!is_continuation)
break;
}
return 0;
}
static int ath12k_dp_rx_process_msdu(struct ath12k *ar,
struct sk_buff *msdu,
struct sk_buff_head *msdu_list,
struct ath12k_dp_rx_info *rx_info)
{
struct ath12k_base *ab = ar->ab;
struct hal_rx_desc *rx_desc, *lrx_desc;
struct ath12k_skb_rxcb *rxcb;
struct sk_buff *last_buf;
u8 l3_pad_bytes;
u16 msdu_len;
int ret;
u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz;
last_buf = ath12k_dp_rx_get_msdu_last_buf(msdu_list, msdu);
if (!last_buf) {
ath12k_warn(ab,
"No valid Rx buffer to access MSDU_END tlv\n");
ret = -EIO;
goto free_out;
}
rx_desc = (struct hal_rx_desc *)msdu->data;
lrx_desc = (struct hal_rx_desc *)last_buf->data;
if (!ath12k_dp_rx_h_msdu_done(ab, lrx_desc)) {
ath12k_warn(ab, "msdu_done bit in msdu_end is not set\n");
ret = -EIO;
goto free_out;
}
rxcb = ATH12K_SKB_RXCB(msdu);
rxcb->rx_desc = rx_desc;
msdu_len = ath12k_dp_rx_h_msdu_len(ab, lrx_desc);
l3_pad_bytes = ath12k_dp_rx_h_l3pad(ab, lrx_desc);
if (rxcb->is_frag) {
skb_pull(msdu, hal_rx_desc_sz);
} else if (!rxcb->is_continuation) {
if ((msdu_len + hal_rx_desc_sz) > DP_RX_BUFFER_SIZE) {
ret = -EINVAL;
ath12k_warn(ab, "invalid msdu len %u\n", msdu_len);
ath12k_dbg_dump(ab, ATH12K_DBG_DATA, NULL, "", rx_desc,
sizeof(*rx_desc));
goto free_out;
}
skb_put(msdu, hal_rx_desc_sz + l3_pad_bytes + msdu_len);
skb_pull(msdu, hal_rx_desc_sz + l3_pad_bytes);
} else {
ret = ath12k_dp_rx_msdu_coalesce(ar, msdu_list,
msdu, last_buf,
l3_pad_bytes, msdu_len);
if (ret) {
ath12k_warn(ab,
"failed to coalesce msdu rx buffer%d\n", ret);
goto free_out;
}
}
if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, rx_desc, msdu))) {
ret = -EINVAL;
goto free_out;
}
ath12k_dp_rx_h_fetch_info(ab, rx_desc, rx_info);
ath12k_dp_rx_h_ppdu(ar, rx_info);
ath12k_dp_rx_h_mpdu(ar, msdu, rx_desc, rx_info);
rx_info->rx_status->flag |= RX_FLAG_SKIP_MONITOR | RX_FLAG_DUP_VALIDATED;
return 0;
free_out:
return ret;
}
static void ath12k_dp_rx_process_received_packets(struct ath12k_base *ab,
struct napi_struct *napi,
struct sk_buff_head *msdu_list,
int ring_id)
{
struct ath12k_hw_group *ag = ab->ag;
struct ieee80211_rx_status rx_status = {};
struct ath12k_skb_rxcb *rxcb;
struct sk_buff *msdu;
struct ath12k *ar;
struct ath12k_hw_link *hw_links = ag->hw_links;
struct ath12k_base *partner_ab;
struct ath12k_dp_rx_info rx_info;
u8 hw_link_id, pdev_id;
int ret;
if (skb_queue_empty(msdu_list))
return;
rx_info.addr2_present = false;
rx_info.rx_status = &rx_status;
rcu_read_lock();
while ((msdu = __skb_dequeue(msdu_list))) {
rxcb = ATH12K_SKB_RXCB(msdu);
hw_link_id = rxcb->hw_link_id;
partner_ab = ath12k_ag_to_ab(ag,
hw_links[hw_link_id].device_id);
pdev_id = ath12k_hw_mac_id_to_pdev_id(partner_ab->hw_params,
hw_links[hw_link_id].pdev_idx);
ar = partner_ab->pdevs[pdev_id].ar;
if (!rcu_dereference(partner_ab->pdevs_active[pdev_id])) {
dev_kfree_skb_any(msdu);
continue;
}
if (test_bit(ATH12K_FLAG_CAC_RUNNING, &ar->dev_flags)) {
dev_kfree_skb_any(msdu);
continue;
}
ret = ath12k_dp_rx_process_msdu(ar, msdu, msdu_list, &rx_info);
if (ret) {
ath12k_dbg(ab, ATH12K_DBG_DATA,
"Unable to process msdu %d", ret);
dev_kfree_skb_any(msdu);
continue;
}
ath12k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_info);
}
rcu_read_unlock();
}
int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id,
struct napi_struct *napi, int budget)
{
struct ath12k_hw_group *ag = ab->ag;
struct list_head rx_desc_used_list[ATH12K_MAX_DEVICES];
struct ath12k_hw_link *hw_links = ag->hw_links;
int num_buffs_reaped[ATH12K_MAX_DEVICES] = {};
struct ath12k_rx_desc_info *desc_info;
struct ath12k_dp *dp = &ab->dp;
struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
struct hal_reo_dest_ring *desc;
struct ath12k_base *partner_ab;
struct sk_buff_head msdu_list;
struct ath12k_skb_rxcb *rxcb;
int total_msdu_reaped = 0;
u8 hw_link_id, device_id;
struct hal_srng *srng;
struct sk_buff *msdu;
bool done = false;
u64 desc_va;
__skb_queue_head_init(&msdu_list);
for (device_id = 0; device_id < ATH12K_MAX_DEVICES; device_id++)
INIT_LIST_HEAD(&rx_desc_used_list[device_id]);
srng = &ab->hal.srng_list[dp->reo_dst_ring[ring_id].ring_id];
spin_lock_bh(&srng->lock);
try_again:
ath12k_hal_srng_access_begin(ab, srng);
while ((desc = ath12k_hal_srng_dst_get_next_entry(ab, srng))) {
struct rx_mpdu_desc *mpdu_info;
struct rx_msdu_desc *msdu_info;
enum hal_reo_dest_ring_push_reason push_reason;
u32 cookie;
cookie = le32_get_bits(desc->buf_addr_info.info1,
BUFFER_ADDR_INFO1_SW_COOKIE);
hw_link_id = le32_get_bits(desc->info0,
HAL_REO_DEST_RING_INFO0_SRC_LINK_ID);
desc_va = ((u64)le32_to_cpu(desc->buf_va_hi) << 32 |
le32_to_cpu(desc->buf_va_lo));
desc_info = (struct ath12k_rx_desc_info *)((unsigned long)desc_va);
device_id = hw_links[hw_link_id].device_id;
partner_ab = ath12k_ag_to_ab(ag, device_id);
if (unlikely(!partner_ab)) {
if (desc_info->skb) {
dev_kfree_skb_any(desc_info->skb);
desc_info->skb = NULL;
}
continue;
}
/* retry manual desc retrieval */
if (!desc_info) {
desc_info = ath12k_dp_get_rx_desc(partner_ab, cookie);
if (!desc_info) {
ath12k_warn(partner_ab, "Invalid cookie in manual descriptor retrieval: 0x%x\n",
cookie);
continue;
}
}
if (desc_info->magic != ATH12K_DP_RX_DESC_MAGIC)
ath12k_warn(ab, "Check HW CC implementation");
msdu = desc_info->skb;
desc_info->skb = NULL;
list_add_tail(&desc_info->list, &rx_desc_used_list[device_id]);
rxcb = ATH12K_SKB_RXCB(msdu);
dma_unmap_single(partner_ab->dev, rxcb->paddr,
msdu->len + skb_tailroom(msdu),
DMA_FROM_DEVICE);
num_buffs_reaped[device_id]++;
ab->device_stats.reo_rx[ring_id][ab->device_id]++;
push_reason = le32_get_bits(desc->info0,
HAL_REO_DEST_RING_INFO0_PUSH_REASON);
if (push_reason !=
HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) {
dev_kfree_skb_any(msdu);
ab->device_stats.hal_reo_error[ring_id]++;
continue;
}
msdu_info = &desc->rx_msdu_info;
mpdu_info = &desc->rx_mpdu_info;
rxcb->is_first_msdu = !!(le32_to_cpu(msdu_info->info0) &
RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU);
rxcb->is_last_msdu = !!(le32_to_cpu(msdu_info->info0) &
RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU);
rxcb->is_continuation = !!(le32_to_cpu(msdu_info->info0) &
RX_MSDU_DESC_INFO0_MSDU_CONTINUATION);
rxcb->hw_link_id = hw_link_id;
rxcb->peer_id = ath12k_dp_rx_get_peer_id(ab, dp->peer_metadata_ver,
mpdu_info->peer_meta_data);
rxcb->tid = le32_get_bits(mpdu_info->info0,
RX_MPDU_DESC_INFO0_TID);
__skb_queue_tail(&msdu_list, msdu);
if (!rxcb->is_continuation) {
total_msdu_reaped++;
done = true;
} else {
done = false;
}
if (total_msdu_reaped >= budget)
break;
}
/* Hw might have updated the head pointer after we cached it.
* In this case, even though there are entries in the ring we'll
* get rx_desc NULL. Give the read another try with updated cached
* head pointer so that we can reap complete MPDU in the current
* rx processing.
*/
if (!done && ath12k_hal_srng_dst_num_free(ab, srng, true)) {
ath12k_hal_srng_access_end(ab, srng);
goto try_again;
}
ath12k_hal_srng_access_end(ab, srng);
spin_unlock_bh(&srng->lock);
if (!total_msdu_reaped)
goto exit;
for (device_id = 0; device_id < ATH12K_MAX_DEVICES; device_id++) {
if (!num_buffs_reaped[device_id])
continue;
partner_ab = ath12k_ag_to_ab(ag, device_id);
rx_ring = &partner_ab->dp.rx_refill_buf_ring;
ath12k_dp_rx_bufs_replenish(partner_ab, rx_ring,
&rx_desc_used_list[device_id],
num_buffs_reaped[device_id]);
}
ath12k_dp_rx_process_received_packets(ab, napi, &msdu_list,
ring_id);
exit:
return total_msdu_reaped;
}
static bool
ath12k_dp_rx_h_defrag_validate_incr_pn(struct ath12k *ar, struct ath12k_dp_rx_tid *rx_tid)
{
@ -188,6 +651,70 @@ static int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar,
return ret;
}
static int ath12k_dp_rx_h_verify_tkip_mic(struct ath12k *ar, struct ath12k_peer *peer,
struct sk_buff *msdu)
{
struct ath12k_base *ab = ar->ab;
struct hal_rx_desc *rx_desc = (struct hal_rx_desc *)msdu->data;
struct ieee80211_rx_status *rxs = IEEE80211_SKB_RXCB(msdu);
struct ieee80211_key_conf *key_conf;
struct ieee80211_hdr *hdr;
struct ath12k_dp_rx_info rx_info;
u8 mic[IEEE80211_CCMP_MIC_LEN];
int head_len, tail_len, ret;
size_t data_len;
u32 hdr_len, hal_rx_desc_sz = ar->ab->hal.hal_desc_sz;
u8 *key, *data;
u8 key_idx;
if (ath12k_dp_rx_h_enctype(ab, rx_desc) != HAL_ENCRYPT_TYPE_TKIP_MIC)
return 0;
rx_info.addr2_present = false;
rx_info.rx_status = rxs;
hdr = (struct ieee80211_hdr *)(msdu->data + hal_rx_desc_sz);
hdr_len = ieee80211_hdrlen(hdr->frame_control);
head_len = hdr_len + hal_rx_desc_sz + IEEE80211_TKIP_IV_LEN;
tail_len = IEEE80211_CCMP_MIC_LEN + IEEE80211_TKIP_ICV_LEN + FCS_LEN;
if (!is_multicast_ether_addr(hdr->addr1))
key_idx = peer->ucast_keyidx;
else
key_idx = peer->mcast_keyidx;
key_conf = peer->keys[key_idx];
data = msdu->data + head_len;
data_len = msdu->len - head_len - tail_len;
key = &key_conf->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY];
ret = ath12k_dp_rx_h_michael_mic(peer->tfm_mmic, key, hdr, data, data_len, mic);
if (ret || memcmp(mic, data + data_len, IEEE80211_CCMP_MIC_LEN))
goto mic_fail;
return 0;
mic_fail:
(ATH12K_SKB_RXCB(msdu))->is_first_msdu = true;
(ATH12K_SKB_RXCB(msdu))->is_last_msdu = true;
ath12k_dp_rx_h_fetch_info(ab, rx_desc, &rx_info);
rxs->flag |= RX_FLAG_MMIC_ERROR | RX_FLAG_MMIC_STRIPPED |
RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED;
skb_pull(msdu, hal_rx_desc_sz);
if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, rx_desc, msdu)))
return -EINVAL;
ath12k_dp_rx_h_ppdu(ar, &rx_info);
ath12k_dp_rx_h_undecap(ar, msdu, rx_desc,
HAL_ENCRYPT_TYPE_TKIP_MIC, rxs, true);
ieee80211_rx(ath12k_ar_to_hw(ar), msdu);
return -EINVAL;
}
static int ath12k_dp_rx_h_defrag(struct ath12k *ar,
struct ath12k_peer *peer,
struct ath12k_dp_rx_tid *rx_tid,

View File

@ -13,6 +13,9 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab,
struct napi_struct *napi, int budget);
int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi,
int budget);
int ath12k_dp_rx_process(struct ath12k_base *ab, int mac_id,
struct napi_struct *napi,
int budget);
int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab);
int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab);
#endif