[PATCH ath12k-ng 05/20] wifi: ath12k: Move Rx error related functions to wifi7 directory
Ripan Deuri
quic_rdeuri at quicinc.com
Thu Aug 28 10:35:38 PDT 2025
From: Pavankumar Nandeshwar <quic_pnandesh at quicinc.com>
Move wifi7 architecture specific Rx error functions from dp_rx.c to
wifi7 directory.
The new wifi7-specific dp_rx.c file will continue to be part of ath12k.ko
temporarily until the corresponding infra for movement to the
ath12k_wifi7.ko arrives in upcoming patches.
Move following architecture specific APIs to wifi7 directory:
ath12k_dp_rx_h_tkip_mic_err
ath12k_dp_rx_h_rxdma_err
ath12k_dp_rx_h_reo_err
ath12k_dp_rx_wbm_err
ath12k_dp_rx_process_wbm_err
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 at quicinc.com>
Signed-off-by: Ripan Deuri <quic_rdeuri at quicinc.com>
---
drivers/net/wireless/ath/ath12k/Makefile | 1 +
drivers/net/wireless/ath/ath12k/dp.c | 2 +-
drivers/net/wireless/ath/ath12k/dp_mon.c | 4 +-
drivers/net/wireless/ath/ath12k/dp_rx.c | 370 +-----------------
drivers/net/wireless/ath/ath12k/dp_rx.h | 18 +-
drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c | 350 +++++++++++++++++
drivers/net/wireless/ath/ath12k/wifi7/dp_rx.h | 14 +
7 files changed, 397 insertions(+), 362 deletions(-)
create mode 100644 drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
create mode 100644 drivers/net/wireless/ath/ath12k/wifi7/dp_rx.h
diff --git a/drivers/net/wireless/ath/ath12k/Makefile b/drivers/net/wireless/ath/ath12k/Makefile
index b34cf83a24eb..d7628bb7af02 100644
--- a/drivers/net/wireless/ath/ath12k/Makefile
+++ b/drivers/net/wireless/ath/ath12k/Makefile
@@ -24,6 +24,7 @@ ath12k-$(CONFIG_ATH12K_AHB) += ahb.o
ath12k-y += wifi7/hal_tx.o \
wifi7/hal_rx.o \
+ wifi7/dp_rx.o
obj-$(CONFIG_ATH12K) += wifi7/
diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c
index a3170e02d4c7..1b4fab3073b0 100644
--- a/drivers/net/wireless/ath/ath12k/dp.c
+++ b/drivers/net/wireless/ath/ath12k/dp.c
@@ -10,7 +10,7 @@
#include "wifi7/hal_tx.h"
#include "hif.h"
#include "debug.h"
-#include "dp_rx.h"
+#include "wifi7/dp_rx.h"
#include "peer.h"
#include "dp_mon.h"
diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c
index 8189e52ed007..b0a0e2a97e8f 100644
--- a/drivers/net/wireless/ath/ath12k/dp_mon.c
+++ b/drivers/net/wireless/ath/ath12k/dp_mon.c
@@ -1,12 +1,12 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "dp_mon.h"
#include "debug.h"
-#include "dp_rx.h"
+#include "wifi7/dp_rx.h"
#include "dp_tx.h"
#include "peer.h"
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
index acd20417b650..453310080182 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -2033,11 +2033,11 @@ static void ath12k_dp_rx_h_undecap_eth(struct ath12k *ar,
ether_addr_copy(ieee80211_get_SA(hdr), sa);
}
-static void ath12k_dp_rx_h_undecap(struct ath12k *ar, struct sk_buff *msdu,
- struct hal_rx_desc *rx_desc,
- enum hal_encrypt_type enctype,
- struct ieee80211_rx_status *status,
- bool decrypted)
+void ath12k_dp_rx_h_undecap(struct ath12k *ar, struct sk_buff *msdu,
+ struct hal_rx_desc *rx_desc,
+ enum hal_encrypt_type enctype,
+ struct ieee80211_rx_status *status,
+ bool decrypted)
{
struct ath12k_base *ab = ar->ab;
u8 decap;
@@ -2323,9 +2323,9 @@ void ath12k_dp_rx_h_ppdu(struct ath12k *ar, struct ath12k_dp_rx_info *rx_info)
ath12k_dp_rx_h_rate(ar, rx_info);
}
-static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *napi,
- struct sk_buff *msdu,
- struct ath12k_dp_rx_info *rx_info)
+void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *napi,
+ struct sk_buff *msdu,
+ struct ath12k_dp_rx_info *rx_info)
{
struct ath12k_base *ab = ar->ab;
struct ieee80211_rx_status *rx_status;
@@ -2395,9 +2395,9 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap
ieee80211_rx_napi(ath12k_ar_to_hw(ar), pubsta, msdu, napi);
}
-static bool ath12k_dp_rx_check_nwifi_hdr_len_valid(struct ath12k_base *ab,
- struct hal_rx_desc *rx_desc,
- struct sk_buff *msdu)
+bool ath12k_dp_rx_check_nwifi_hdr_len_valid(struct ath12k_base *ab,
+ struct hal_rx_desc *rx_desc,
+ struct sk_buff *msdu)
{
struct ieee80211_hdr *hdr;
u8 decap_type;
@@ -3584,9 +3584,9 @@ static void ath12k_dp_rx_null_q_desc_sg_drop(struct ath12k *ar,
}
}
-static int ath12k_dp_rx_h_null_q_desc(struct ath12k *ar, struct sk_buff *msdu,
- struct ath12k_dp_rx_info *rx_info,
- struct sk_buff_head *msdu_list)
+int ath12k_dp_rx_h_null_q_desc(struct ath12k *ar, struct sk_buff *msdu,
+ struct ath12k_dp_rx_info *rx_info,
+ struct sk_buff_head *msdu_list)
{
struct ath12k_base *ab = ar->ab;
u16 msdu_len;
@@ -3654,348 +3654,6 @@ static int ath12k_dp_rx_h_null_q_desc(struct ath12k *ar, struct sk_buff *msdu,
return 0;
}
-static bool ath12k_dp_rx_h_reo_err(struct ath12k *ar, struct sk_buff *msdu,
- struct ath12k_dp_rx_info *rx_info,
- struct sk_buff_head *msdu_list)
-{
- struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
- bool drop = false;
-
- ar->ab->device_stats.reo_error[rxcb->err_code]++;
-
- switch (rxcb->err_code) {
- case HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO:
- if (ath12k_dp_rx_h_null_q_desc(ar, msdu, rx_info, msdu_list))
- drop = true;
- break;
- case HAL_REO_DEST_RING_ERROR_CODE_PN_CHECK_FAILED:
- /* TODO: Do not drop PN failed packets in the driver;
- * instead, it is good to drop such packets in mac80211
- * after incrementing the replay counters.
- */
- fallthrough;
- default:
- /* TODO: Review other errors and process them to mac80211
- * as appropriate.
- */
- drop = true;
- break;
- }
-
- return drop;
-}
-
-static bool ath12k_dp_rx_h_tkip_mic_err(struct ath12k *ar, struct sk_buff *msdu,
- struct ath12k_dp_rx_info *rx_info)
-{
- struct ath12k_base *ab = ar->ab;
- u16 msdu_len;
- struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data;
- u8 l3pad_bytes;
- struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
- u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz;
-
- rxcb->is_first_msdu = ath12k_dp_rx_h_first_msdu(ab, desc);
- rxcb->is_last_msdu = ath12k_dp_rx_h_last_msdu(ab, desc);
-
- l3pad_bytes = ath12k_dp_rx_h_l3pad(ab, desc);
- msdu_len = ath12k_dp_rx_h_msdu_len(ab, desc);
-
- if ((hal_rx_desc_sz + l3pad_bytes + msdu_len) > DP_RX_BUFFER_SIZE) {
- ath12k_dbg(ab, ATH12K_DBG_DATA,
- "invalid msdu len in tkip mic err %u\n", msdu_len);
- ath12k_dbg_dump(ab, ATH12K_DBG_DATA, NULL, "", desc,
- sizeof(*desc));
- return true;
- }
-
- skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
- skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
-
- if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, desc, msdu)))
- return true;
-
- ath12k_dp_rx_h_ppdu(ar, rx_info);
-
- rx_info->rx_status->flag |= (RX_FLAG_MMIC_STRIPPED | RX_FLAG_MMIC_ERROR |
- RX_FLAG_DECRYPTED);
-
- ath12k_dp_rx_h_undecap(ar, msdu, desc,
- HAL_ENCRYPT_TYPE_TKIP_MIC, rx_info->rx_status, false);
- return false;
-}
-
-static bool ath12k_dp_rx_h_rxdma_err(struct ath12k *ar, struct sk_buff *msdu,
- struct ath12k_dp_rx_info *rx_info)
-{
- struct ath12k_base *ab = ar->ab;
- struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
- struct hal_rx_desc *rx_desc = (struct hal_rx_desc *)msdu->data;
- bool drop = false;
- u32 err_bitmap;
-
- ar->ab->device_stats.rxdma_error[rxcb->err_code]++;
-
- switch (rxcb->err_code) {
- case HAL_REO_ENTR_RING_RXDMA_ECODE_DECRYPT_ERR:
- case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR:
- err_bitmap = ath12k_dp_rx_h_mpdu_err(ab, rx_desc);
- if (err_bitmap & HAL_RX_MPDU_ERR_TKIP_MIC) {
- ath12k_dp_rx_h_fetch_info(ab, rx_desc, rx_info);
- drop = ath12k_dp_rx_h_tkip_mic_err(ar, msdu, rx_info);
- break;
- }
- fallthrough;
- default:
- /* TODO: Review other rxdma error code to check if anything is
- * worth reporting to mac80211
- */
- drop = true;
- break;
- }
-
- return drop;
-}
-
-static void ath12k_dp_rx_wbm_err(struct ath12k *ar,
- struct napi_struct *napi,
- struct sk_buff *msdu,
- struct sk_buff_head *msdu_list)
-{
- struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
- struct ieee80211_rx_status rxs = {};
- struct ath12k_dp_rx_info rx_info;
- bool drop = true;
-
- rx_info.addr2_present = false;
- rx_info.rx_status = &rxs;
-
- switch (rxcb->err_rel_src) {
- case HAL_WBM_REL_SRC_MODULE_REO:
- drop = ath12k_dp_rx_h_reo_err(ar, msdu, &rx_info, msdu_list);
- break;
- case HAL_WBM_REL_SRC_MODULE_RXDMA:
- drop = ath12k_dp_rx_h_rxdma_err(ar, msdu, &rx_info);
- break;
- default:
- /* msdu will get freed */
- break;
- }
-
- if (drop) {
- dev_kfree_skb_any(msdu);
- return;
- }
-
- rx_info.rx_status->flag |= RX_FLAG_SKIP_MONITOR;
-
- ath12k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_info);
-}
-
-int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab,
- struct napi_struct *napi, int budget)
-{
- struct list_head rx_desc_used_list[ATH12K_MAX_DEVICES];
- struct ath12k_hw_group *ag = ab->ag;
- struct ath12k *ar;
- struct ath12k_dp *dp = &ab->dp;
- struct dp_rxdma_ring *rx_ring;
- struct hal_rx_wbm_rel_info err_info;
- struct hal_srng *srng;
- struct sk_buff *msdu;
- struct sk_buff_head msdu_list, scatter_msdu_list;
- struct ath12k_skb_rxcb *rxcb;
- void *rx_desc;
- int num_buffs_reaped[ATH12K_MAX_DEVICES] = {};
- int total_num_buffs_reaped = 0;
- struct ath12k_rx_desc_info *desc_info;
- struct ath12k_device_dp_stats *device_stats = &ab->device_stats;
- struct ath12k_hw_link *hw_links = ag->hw_links;
- struct ath12k_base *partner_ab;
- u8 hw_link_id, device_id;
- int ret, pdev_id;
- struct hal_rx_desc *msdu_data;
-
- __skb_queue_head_init(&msdu_list);
- __skb_queue_head_init(&scatter_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->rx_rel_ring.ring_id];
- spin_lock_bh(&srng->lock);
-
- ath12k_hal_srng_access_begin(ab, srng);
-
- while (budget) {
- rx_desc = ath12k_hal_srng_dst_get_next_entry(ab, srng);
- if (!rx_desc)
- break;
-
- ret = ath12k_hal_wbm_desc_parse_err(ab, rx_desc, &err_info);
- if (ret) {
- ath12k_warn(ab,
- "failed to parse rx error in wbm_rel ring desc %d\n",
- ret);
- continue;
- }
-
- desc_info = err_info.rx_desc;
-
- /* retry manual desc retrieval if hw cc is not done */
- if (!desc_info) {
- desc_info = ath12k_dp_get_rx_desc(ab, err_info.cookie);
- if (!desc_info) {
- ath12k_warn(ab, "Invalid cookie in DP WBM rx error descriptor retrieval: 0x%x\n",
- err_info.cookie);
- continue;
- }
- }
-
- if (desc_info->magic != ATH12K_DP_RX_DESC_MAGIC)
- ath12k_warn(ab, "WBM RX err, Check HW CC implementation");
-
- msdu = desc_info->skb;
- desc_info->skb = NULL;
-
- device_id = desc_info->device_id;
- partner_ab = ath12k_ag_to_ab(ag, device_id);
- if (unlikely(!partner_ab)) {
- dev_kfree_skb_any(msdu);
-
- /* In any case continuation bit is set
- * in the previous record, cleanup scatter_msdu_list
- */
- ath12k_dp_clean_up_skb_list(&scatter_msdu_list);
- continue;
- }
-
- 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]++;
- total_num_buffs_reaped++;
-
- if (!err_info.continuation)
- budget--;
-
- if (err_info.push_reason !=
- HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED) {
- dev_kfree_skb_any(msdu);
- continue;
- }
-
- msdu_data = (struct hal_rx_desc *)msdu->data;
- rxcb->err_rel_src = err_info.err_rel_src;
- rxcb->err_code = err_info.err_code;
- rxcb->is_first_msdu = err_info.first_msdu;
- rxcb->is_last_msdu = err_info.last_msdu;
- rxcb->is_continuation = err_info.continuation;
- rxcb->rx_desc = msdu_data;
-
- if (err_info.continuation) {
- __skb_queue_tail(&scatter_msdu_list, msdu);
- continue;
- }
-
- hw_link_id = ath12k_dp_rx_get_msdu_src_link(partner_ab,
- msdu_data);
- if (hw_link_id >= ATH12K_GROUP_MAX_RADIO) {
- dev_kfree_skb_any(msdu);
-
- /* In any case continuation bit is set
- * in the previous record, cleanup scatter_msdu_list
- */
- ath12k_dp_clean_up_skb_list(&scatter_msdu_list);
- continue;
- }
-
- if (!skb_queue_empty(&scatter_msdu_list)) {
- struct sk_buff *msdu;
-
- skb_queue_walk(&scatter_msdu_list, msdu) {
- rxcb = ATH12K_SKB_RXCB(msdu);
- rxcb->hw_link_id = hw_link_id;
- }
-
- skb_queue_splice_tail_init(&scatter_msdu_list,
- &msdu_list);
- }
-
- rxcb = ATH12K_SKB_RXCB(msdu);
- rxcb->hw_link_id = hw_link_id;
- __skb_queue_tail(&msdu_list, msdu);
- }
-
- /* In any case continuation bit is set in the
- * last record, cleanup scatter_msdu_list
- */
- ath12k_dp_clean_up_skb_list(&scatter_msdu_list);
-
- ath12k_hal_srng_access_end(ab, srng);
-
- spin_unlock_bh(&srng->lock);
-
- if (!total_num_buffs_reaped)
- goto done;
-
- 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(ab, rx_ring,
- &rx_desc_used_list[device_id],
- num_buffs_reaped[device_id]);
- }
-
- rcu_read_lock();
- while ((msdu = __skb_dequeue(&msdu_list))) {
- rxcb = ATH12K_SKB_RXCB(msdu);
- hw_link_id = rxcb->hw_link_id;
-
- device_id = hw_links[hw_link_id].device_id;
- partner_ab = ath12k_ag_to_ab(ag, device_id);
- if (unlikely(!partner_ab)) {
- ath12k_dbg(ab, ATH12K_DBG_DATA,
- "Unable to process WBM error msdu due to invalid hw link id %d device id %d\n",
- hw_link_id, device_id);
- dev_kfree_skb_any(msdu);
- continue;
- }
-
- 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 (!ar || !rcu_dereference(ar->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;
- }
-
- if (rxcb->err_rel_src < HAL_WBM_REL_SRC_MODULE_MAX) {
- device_id = ar->ab->device_id;
- device_stats->rx_wbm_rel_source[rxcb->err_rel_src][device_id]++;
- }
-
- ath12k_dp_rx_wbm_err(ar, napi, msdu, &msdu_list);
- }
- rcu_read_unlock();
-done:
- return total_num_buffs_reaped;
-}
-
void ath12k_dp_rx_process_reo_status(struct ath12k_base *ab)
{
struct ath12k_dp *dp = &ab->dp;
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h
index 61861c63ecbf..1909f9070d46 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.h
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.h
@@ -340,6 +340,20 @@ static inline void ath12k_dp_clean_up_skb_list(struct sk_buff_head *skb_list)
dev_kfree_skb_any(skb);
}
+void ath12k_dp_rx_h_undecap(struct ath12k *ar, struct sk_buff *msdu,
+ struct hal_rx_desc *rx_desc,
+ enum hal_encrypt_type enctype,
+ struct ieee80211_rx_status *status,
+ bool decrypted);
+void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *napi,
+ struct sk_buff *msdu,
+ struct ath12k_dp_rx_info *rx_info);
+bool ath12k_dp_rx_check_nwifi_hdr_len_valid(struct ath12k_base *ab,
+ struct hal_rx_desc *rx_desc,
+ struct sk_buff *msdu);
+int ath12k_dp_rx_h_null_q_desc(struct ath12k *ar, struct sk_buff *msdu,
+ struct ath12k_dp_rx_info *rx_info,
+ struct sk_buff_head *msdu_list);
int ath12k_dp_rx_ampdu_start(struct ath12k *ar,
struct ieee80211_ampdu_params *params,
u8 link_id);
@@ -367,8 +381,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_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,
@@ -390,7 +402,6 @@ u8 ath12k_dp_rx_h_decap_type(struct ath12k_base *ab,
struct hal_rx_desc *desc);
u32 ath12k_dp_rx_h_mpdu_err(struct ath12k_base *ab,
struct hal_rx_desc *desc);
-void ath12k_dp_rx_h_ppdu(struct ath12k *ar, struct ath12k_dp_rx_info *rx_info);
int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab);
int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab);
@@ -411,4 +422,5 @@ int ath12k_dp_rx_link_desc_return(struct ath12k_base *ab,
enum hal_wbm_rel_bm_act action);
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);
#endif /* ATH12K_DP_RX_H */
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
new file mode 100644
index 000000000000..26539a4d4b30
--- /dev/null
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include "dp_rx.h"
+#include "../dp_tx.h"
+
+static bool ath12k_dp_rx_h_tkip_mic_err(struct ath12k *ar, struct sk_buff *msdu,
+ struct ath12k_dp_rx_info *rx_info)
+{
+ struct ath12k_base *ab = ar->ab;
+ u16 msdu_len;
+ struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data;
+ u8 l3pad_bytes;
+ struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
+ u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz;
+
+ rxcb->is_first_msdu = ath12k_dp_rx_h_first_msdu(ab, desc);
+ rxcb->is_last_msdu = ath12k_dp_rx_h_last_msdu(ab, desc);
+
+ l3pad_bytes = ath12k_dp_rx_h_l3pad(ab, desc);
+ msdu_len = ath12k_dp_rx_h_msdu_len(ab, desc);
+
+ if ((hal_rx_desc_sz + l3pad_bytes + msdu_len) > DP_RX_BUFFER_SIZE) {
+ ath12k_dbg(ab, ATH12K_DBG_DATA,
+ "invalid msdu len in tkip mic err %u\n", msdu_len);
+ ath12k_dbg_dump(ab, ATH12K_DBG_DATA, NULL, "", desc,
+ sizeof(*desc));
+ return true;
+ }
+
+ skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
+ skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
+
+ if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, desc, msdu)))
+ return true;
+
+ ath12k_dp_rx_h_ppdu(ar, rx_info);
+
+ rx_info->rx_status->flag |= (RX_FLAG_MMIC_STRIPPED | RX_FLAG_MMIC_ERROR |
+ RX_FLAG_DECRYPTED);
+
+ ath12k_dp_rx_h_undecap(ar, msdu, desc,
+ HAL_ENCRYPT_TYPE_TKIP_MIC, rx_info->rx_status, false);
+ return false;
+}
+
+static bool ath12k_dp_rx_h_rxdma_err(struct ath12k *ar, struct sk_buff *msdu,
+ struct ath12k_dp_rx_info *rx_info)
+{
+ struct ath12k_base *ab = ar->ab;
+ struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
+ struct hal_rx_desc *rx_desc = (struct hal_rx_desc *)msdu->data;
+ bool drop = false;
+ u32 err_bitmap;
+
+ ar->ab->device_stats.rxdma_error[rxcb->err_code]++;
+
+ switch (rxcb->err_code) {
+ case HAL_REO_ENTR_RING_RXDMA_ECODE_DECRYPT_ERR:
+ case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR:
+ err_bitmap = ath12k_dp_rx_h_mpdu_err(ab, rx_desc);
+ if (err_bitmap & HAL_RX_MPDU_ERR_TKIP_MIC) {
+ ath12k_dp_rx_h_fetch_info(ab, rx_desc, rx_info);
+ drop = ath12k_dp_rx_h_tkip_mic_err(ar, msdu, rx_info);
+ break;
+ }
+ fallthrough;
+ default:
+ /* TODO: Review other rxdma error code to check if anything is
+ * worth reporting to mac80211
+ */
+ drop = true;
+ break;
+ }
+
+ return drop;
+}
+
+static bool ath12k_dp_rx_h_reo_err(struct ath12k *ar, struct sk_buff *msdu,
+ struct ath12k_dp_rx_info *rx_info,
+ struct sk_buff_head *msdu_list)
+{
+ struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
+ bool drop = false;
+
+ ar->ab->device_stats.reo_error[rxcb->err_code]++;
+
+ switch (rxcb->err_code) {
+ case HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO:
+ if (ath12k_dp_rx_h_null_q_desc(ar, msdu, rx_info, msdu_list))
+ drop = true;
+ break;
+ case HAL_REO_DEST_RING_ERROR_CODE_PN_CHECK_FAILED:
+ /* TODO: Do not drop PN failed packets in the driver;
+ * instead, it is good to drop such packets in mac80211
+ * after incrementing the replay counters.
+ */
+ fallthrough;
+ default:
+ /* TODO: Review other errors and process them to mac80211
+ * as appropriate.
+ */
+ drop = true;
+ break;
+ }
+
+ return drop;
+}
+
+static void ath12k_dp_rx_wbm_err(struct ath12k *ar,
+ struct napi_struct *napi,
+ struct sk_buff *msdu,
+ struct sk_buff_head *msdu_list)
+{
+ struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
+ struct ieee80211_rx_status rxs = {};
+ struct ath12k_dp_rx_info rx_info;
+ bool drop = true;
+
+ rx_info.addr2_present = false;
+ rx_info.rx_status = &rxs;
+
+ switch (rxcb->err_rel_src) {
+ case HAL_WBM_REL_SRC_MODULE_REO:
+ drop = ath12k_dp_rx_h_reo_err(ar, msdu, &rx_info, msdu_list);
+ break;
+ case HAL_WBM_REL_SRC_MODULE_RXDMA:
+ drop = ath12k_dp_rx_h_rxdma_err(ar, msdu, &rx_info);
+ break;
+ default:
+ /* msdu will get freed */
+ break;
+ }
+
+ if (drop) {
+ dev_kfree_skb_any(msdu);
+ return;
+ }
+
+ rx_info.rx_status->flag |= RX_FLAG_SKIP_MONITOR;
+
+ ath12k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_info);
+}
+
+int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab,
+ struct napi_struct *napi, int budget)
+{
+ struct list_head rx_desc_used_list[ATH12K_MAX_DEVICES];
+ struct ath12k_hw_group *ag = ab->ag;
+ struct ath12k *ar;
+ struct ath12k_dp *dp = &ab->dp;
+ struct dp_rxdma_ring *rx_ring;
+ struct hal_rx_wbm_rel_info err_info;
+ struct hal_srng *srng;
+ struct sk_buff *msdu;
+ struct sk_buff_head msdu_list, scatter_msdu_list;
+ struct ath12k_skb_rxcb *rxcb;
+ void *rx_desc;
+ int num_buffs_reaped[ATH12K_MAX_DEVICES] = {};
+ int total_num_buffs_reaped = 0;
+ struct ath12k_rx_desc_info *desc_info;
+ struct ath12k_device_dp_stats *device_stats = &ab->device_stats;
+ struct ath12k_hw_link *hw_links = ag->hw_links;
+ struct ath12k_base *partner_ab;
+ u8 hw_link_id, device_id;
+ int ret, pdev_id;
+ struct hal_rx_desc *msdu_data;
+
+ __skb_queue_head_init(&msdu_list);
+ __skb_queue_head_init(&scatter_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->rx_rel_ring.ring_id];
+ spin_lock_bh(&srng->lock);
+
+ ath12k_hal_srng_access_begin(ab, srng);
+
+ while (budget) {
+ rx_desc = ath12k_hal_srng_dst_get_next_entry(ab, srng);
+ if (!rx_desc)
+ break;
+
+ ret = ath12k_hal_wbm_desc_parse_err(ab, rx_desc, &err_info);
+ if (ret) {
+ ath12k_warn(ab,
+ "failed to parse rx error in wbm_rel ring desc %d\n",
+ ret);
+ continue;
+ }
+
+ desc_info = err_info.rx_desc;
+
+ /* retry manual desc retrieval if hw cc is not done */
+ if (!desc_info) {
+ desc_info = ath12k_dp_get_rx_desc(ab, err_info.cookie);
+ if (!desc_info) {
+ ath12k_warn(ab, "Invalid cookie in DP WBM rx error descriptor retrieval: 0x%x\n",
+ err_info.cookie);
+ continue;
+ }
+ }
+
+ if (desc_info->magic != ATH12K_DP_RX_DESC_MAGIC)
+ ath12k_warn(ab, "WBM RX err, Check HW CC implementation");
+
+ msdu = desc_info->skb;
+ desc_info->skb = NULL;
+
+ device_id = desc_info->device_id;
+ partner_ab = ath12k_ag_to_ab(ag, device_id);
+ if (unlikely(!partner_ab)) {
+ dev_kfree_skb_any(msdu);
+
+ /* In any case continuation bit is set
+ * in the previous record, cleanup scatter_msdu_list
+ */
+ ath12k_dp_clean_up_skb_list(&scatter_msdu_list);
+ continue;
+ }
+
+ 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]++;
+ total_num_buffs_reaped++;
+
+ if (!err_info.continuation)
+ budget--;
+
+ if (err_info.push_reason !=
+ HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED) {
+ dev_kfree_skb_any(msdu);
+ continue;
+ }
+
+ msdu_data = (struct hal_rx_desc *)msdu->data;
+ rxcb->err_rel_src = err_info.err_rel_src;
+ rxcb->err_code = err_info.err_code;
+ rxcb->is_first_msdu = err_info.first_msdu;
+ rxcb->is_last_msdu = err_info.last_msdu;
+ rxcb->is_continuation = err_info.continuation;
+ rxcb->rx_desc = msdu_data;
+
+ if (err_info.continuation) {
+ __skb_queue_tail(&scatter_msdu_list, msdu);
+ continue;
+ }
+
+ hw_link_id = ath12k_dp_rx_get_msdu_src_link(partner_ab,
+ msdu_data);
+ if (hw_link_id >= ATH12K_GROUP_MAX_RADIO) {
+ dev_kfree_skb_any(msdu);
+
+ /* In any case continuation bit is set
+ * in the previous record, cleanup scatter_msdu_list
+ */
+ ath12k_dp_clean_up_skb_list(&scatter_msdu_list);
+ continue;
+ }
+
+ if (!skb_queue_empty(&scatter_msdu_list)) {
+ struct sk_buff *msdu;
+
+ skb_queue_walk(&scatter_msdu_list, msdu) {
+ rxcb = ATH12K_SKB_RXCB(msdu);
+ rxcb->hw_link_id = hw_link_id;
+ }
+
+ skb_queue_splice_tail_init(&scatter_msdu_list,
+ &msdu_list);
+ }
+
+ rxcb = ATH12K_SKB_RXCB(msdu);
+ rxcb->hw_link_id = hw_link_id;
+ __skb_queue_tail(&msdu_list, msdu);
+ }
+
+ /* In any case continuation bit is set in the
+ * last record, cleanup scatter_msdu_list
+ */
+ ath12k_dp_clean_up_skb_list(&scatter_msdu_list);
+
+ ath12k_hal_srng_access_end(ab, srng);
+
+ spin_unlock_bh(&srng->lock);
+
+ if (!total_num_buffs_reaped)
+ goto done;
+
+ 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(ab, rx_ring,
+ &rx_desc_used_list[device_id],
+ num_buffs_reaped[device_id]);
+ }
+
+ rcu_read_lock();
+ while ((msdu = __skb_dequeue(&msdu_list))) {
+ rxcb = ATH12K_SKB_RXCB(msdu);
+ hw_link_id = rxcb->hw_link_id;
+
+ device_id = hw_links[hw_link_id].device_id;
+ partner_ab = ath12k_ag_to_ab(ag, device_id);
+ if (unlikely(!partner_ab)) {
+ ath12k_dbg(ab, ATH12K_DBG_DATA,
+ "Unable to process WBM error msdu due to invalid hw link id %d device id %d\n",
+ hw_link_id, device_id);
+ dev_kfree_skb_any(msdu);
+ continue;
+ }
+
+ 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 (!ar || !rcu_dereference(ar->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;
+ }
+
+ if (rxcb->err_rel_src < HAL_WBM_REL_SRC_MODULE_MAX) {
+ device_id = ar->ab->device_id;
+ device_stats->rx_wbm_rel_source[rxcb->err_rel_src][device_id]++;
+ }
+
+ ath12k_dp_rx_wbm_err(ar, napi, msdu, &msdu_list);
+ }
+ rcu_read_unlock();
+done:
+ return total_num_buffs_reaped;
+}
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.h b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.h
new file mode 100644
index 000000000000..a6da98962345
--- /dev/null
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+#ifndef ATH12K_DP_RX_WIFI7_H
+#define ATH12K_DP_RX_WIFI7_H
+
+#include "../core.h"
+#include "../dp_rx.h"
+
+int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab,
+ struct napi_struct *napi, int budget);
+#endif
--
2.34.1
More information about the ath12k
mailing list