]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
wifi: ath11k: fix rx completion meta data corruption
authorJohan Hovold <johan+linaro@kernel.org>
Fri, 21 Mar 2025 14:53:02 +0000 (15:53 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 27 Jun 2025 10:11:15 +0000 (11:11 +0100)
commit ab52e3e44fe9b666281752e2481d11e25b0e3fdd upstream.

Add the missing memory barrier to make sure that the REO dest ring
descriptor is read after the head pointer to avoid using stale data on
weakly ordered architectures like aarch64.

This may fix the ring-buffer corruption worked around by commit
f9fff67d2d7c ("wifi: ath11k: Fix SKB corruption in REO destination
ring") by silently discarding data, and may possibly also address user
reported errors like:

ath11k_pci 0006:01:00.0: msdu_done bit in attention is not set

Tested-on: WCN6855 hw2.1 WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.41

Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
Cc: stable@vger.kernel.org # 5.6
Link: https://bugzilla.kernel.org/show_bug.cgi?id=218005
Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
Tested-by: Clayton Craft <clayton@craftyguy.net>
Link: https://patch.msgid.link/20250321145302.4775-1-johan+linaro@kernel.org
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/net/wireless/ath/ath11k/dp_rx.c

index bfb8e7b1a300c6cadd508b5e320b93de73aea550..007d869590423501237f4c0e1bdd4431df8272d0 100644 (file)
@@ -2637,7 +2637,7 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id,
        struct ath11k *ar;
        struct hal_reo_dest_ring *desc;
        enum hal_reo_dest_ring_push_reason push_reason;
-       u32 cookie;
+       u32 cookie, info0, rx_msdu_info0, rx_mpdu_info0;
        int i;
 
        for (i = 0; i < MAX_RADIOS; i++)
@@ -2650,11 +2650,14 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id,
 try_again:
        ath11k_hal_srng_access_begin(ab, srng);
 
+       /* Make sure descriptor is read after the head pointer. */
+       dma_rmb();
+
        while (likely(desc =
              (struct hal_reo_dest_ring *)ath11k_hal_srng_dst_get_next_entry(ab,
                                                                             srng))) {
                cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
-                                  desc->buf_addr_info.info1);
+                                  READ_ONCE(desc->buf_addr_info.info1));
                buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID,
                                   cookie);
                mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, cookie);
@@ -2683,8 +2686,9 @@ try_again:
 
                num_buffs_reaped[mac_id]++;
 
+               info0 = READ_ONCE(desc->info0);
                push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON,
-                                       desc->info0);
+                                       info0);
                if (unlikely(push_reason !=
                             HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION)) {
                        dev_kfree_skb_any(msdu);
@@ -2692,18 +2696,21 @@ try_again:
                        continue;
                }
 
-               rxcb->is_first_msdu = !!(desc->rx_msdu_info.info0 &
+               rx_msdu_info0 = READ_ONCE(desc->rx_msdu_info.info0);
+               rx_mpdu_info0 = READ_ONCE(desc->rx_mpdu_info.info0);
+
+               rxcb->is_first_msdu = !!(rx_msdu_info0 &
                                         RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU);
-               rxcb->is_last_msdu = !!(desc->rx_msdu_info.info0 &
+               rxcb->is_last_msdu = !!(rx_msdu_info0 &
                                        RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU);
-               rxcb->is_continuation = !!(desc->rx_msdu_info.info0 &
+               rxcb->is_continuation = !!(rx_msdu_info0 &
                                           RX_MSDU_DESC_INFO0_MSDU_CONTINUATION);
                rxcb->peer_id = FIELD_GET(RX_MPDU_DESC_META_DATA_PEER_ID,
-                                         desc->rx_mpdu_info.meta_data);
+                                         READ_ONCE(desc->rx_mpdu_info.meta_data));
                rxcb->seq_no = FIELD_GET(RX_MPDU_DESC_INFO0_SEQ_NUM,
-                                        desc->rx_mpdu_info.info0);
+                                        rx_mpdu_info0);
                rxcb->tid = FIELD_GET(HAL_REO_DEST_RING_INFO0_RX_QUEUE_NUM,
-                                     desc->info0);
+                                     info0);
 
                rxcb->mac_id = mac_id;
                __skb_queue_tail(&msdu_list[mac_id], msdu);