]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: aquantia: Add missing descriptor cache invalidation on ATL2
authorKai-Heng Feng <kaihengf@nvidia.com>
Thu, 20 Nov 2025 04:15:33 +0000 (12:15 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 25 Nov 2025 11:15:12 +0000 (12:15 +0100)
ATL2 hardware was missing descriptor cache invalidation in hw_stop(),
causing SMMU translation faults during device shutdown and module removal:
[   70.355743] arm-smmu-v3 arm-smmu-v3.5.auto: event 0x10 received:
[   70.361893] arm-smmu-v3 arm-smmu-v3.5.auto:  0x0002060000000010
[   70.367948] arm-smmu-v3 arm-smmu-v3.5.auto:  0x0000020000000000
[   70.374002] arm-smmu-v3 arm-smmu-v3.5.auto:  0x00000000ff9bc000
[   70.380055] arm-smmu-v3 arm-smmu-v3.5.auto:  0x0000000000000000
[   70.386109] arm-smmu-v3 arm-smmu-v3.5.auto: event: F_TRANSLATION client: 0001:06:00.0 sid: 0x20600 ssid: 0x0 iova: 0xff9bc000 ipa: 0x0
[   70.398531] arm-smmu-v3 arm-smmu-v3.5.auto: unpriv data write s1 "Input address caused fault" stag: 0x0

Commit 7a1bb49461b1 ("net: aquantia: fix potential IOMMU fault after
driver unbind") and commit ed4d81c4b3f2 ("net: aquantia: when cleaning
hw cache it should be toggled") fixed cache invalidation for ATL B0, but
ATL2 was left with only interrupt disabling. This allowed hardware to
write to cached descriptors after DMA memory was unmapped, triggering
SMMU faults. Once cache invalidation is applied to ATL2, the translation
fault can't be observed anymore.

Add shared aq_hw_invalidate_descriptor_cache() helper and use it in both
ATL B0 and ATL2 hw_stop() implementations for consistent behavior.

Fixes: e54dcf4bba3e ("net: atlantic: basic A2 init/deinit hw_ops")
Tested-by: Carol Soto <csoto@nvidia.com>
Signed-off-by: Kai-Heng Feng <kaihengf@nvidia.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20251120041537.62184-1-kaihengf@nvidia.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/aquantia/atlantic/aq_hw_utils.c
drivers/net/ethernet/aquantia/atlantic/aq_hw_utils.h
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c

index 1921741f7311daaef2592bf4bdbc9725d42b2b04..18b08277d2e1a8b3f3235c0748356e58bae1c614 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "aq_hw.h"
 #include "aq_nic.h"
+#include "hw_atl/hw_atl_llh.h"
 
 void aq_hw_write_reg_bit(struct aq_hw_s *aq_hw, u32 addr, u32 msk,
                         u32 shift, u32 val)
@@ -81,6 +82,27 @@ void aq_hw_write_reg64(struct aq_hw_s *hw, u32 reg, u64 value)
                lo_hi_writeq(value, hw->mmio + reg);
 }
 
+int aq_hw_invalidate_descriptor_cache(struct aq_hw_s *hw)
+{
+       int err;
+       u32 val;
+
+       /* Invalidate Descriptor Cache to prevent writing to the cached
+        * descriptors and to the data pointer of those descriptors
+        */
+       hw_atl_rdm_rx_dma_desc_cache_init_tgl(hw);
+
+       err = aq_hw_err_from_flags(hw);
+       if (err)
+               goto err_exit;
+
+       readx_poll_timeout_atomic(hw_atl_rdm_rx_dma_desc_cache_init_done_get,
+                                 hw, val, val == 1, 1000U, 10000U);
+
+err_exit:
+       return err;
+}
+
 int aq_hw_err_from_flags(struct aq_hw_s *hw)
 {
        int err = 0;
index ffa6e4067c21187f206079667d867475d380f609..d89c63d88e4a44abff4bb3f0b6ceffb67cbc2653 100644 (file)
@@ -35,6 +35,7 @@ u32 aq_hw_read_reg(struct aq_hw_s *hw, u32 reg);
 void aq_hw_write_reg(struct aq_hw_s *hw, u32 reg, u32 value);
 u64 aq_hw_read_reg64(struct aq_hw_s *hw, u32 reg);
 void aq_hw_write_reg64(struct aq_hw_s *hw, u32 reg, u64 value);
+int aq_hw_invalidate_descriptor_cache(struct aq_hw_s *hw);
 int aq_hw_err_from_flags(struct aq_hw_s *hw);
 int aq_hw_num_tcs(struct aq_hw_s *hw);
 int aq_hw_q_per_tc(struct aq_hw_s *hw);
index 493432d036b9a28d6c5cb98912cf618eef605908..c7895bfb2ecf819f4e08121b1d986531a1a77b25 100644 (file)
@@ -1198,26 +1198,9 @@ static int hw_atl_b0_hw_interrupt_moderation_set(struct aq_hw_s *self)
 
 static int hw_atl_b0_hw_stop(struct aq_hw_s *self)
 {
-       int err;
-       u32 val;
-
        hw_atl_b0_hw_irq_disable(self, HW_ATL_B0_INT_MASK);
 
-       /* Invalidate Descriptor Cache to prevent writing to the cached
-        * descriptors and to the data pointer of those descriptors
-        */
-       hw_atl_rdm_rx_dma_desc_cache_init_tgl(self);
-
-       err = aq_hw_err_from_flags(self);
-
-       if (err)
-               goto err_exit;
-
-       readx_poll_timeout_atomic(hw_atl_rdm_rx_dma_desc_cache_init_done_get,
-                                 self, val, val == 1, 1000U, 10000U);
-
-err_exit:
-       return err;
+       return aq_hw_invalidate_descriptor_cache(self);
 }
 
 int hw_atl_b0_hw_ring_tx_stop(struct aq_hw_s *self, struct aq_ring_s *ring)
index b0ed572e88c67a9eeec2d62d935aec8ec34722de..0ce9caae8799c7ff1ab5f29a56b137ba71e04b35 100644 (file)
@@ -759,7 +759,7 @@ static int hw_atl2_hw_stop(struct aq_hw_s *self)
 {
        hw_atl_b0_hw_irq_disable(self, HW_ATL2_INT_MASK);
 
-       return 0;
+       return aq_hw_invalidate_descriptor_cache(self);
 }
 
 static struct aq_stats_s *hw_atl2_utils_get_hw_stats(struct aq_hw_s *self)