mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 01:49:46 +00:00
net: aquantia: Add missing descriptor cache invalidation on ATL2
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 Commit7a1bb49461("net: aquantia: fix potential IOMMU fault after driver unbind") and commited4d81c4b3("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:e54dcf4bba("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>
This commit is contained in:
committed by
Paolo Abeni
parent
4fe5a00ec7
commit
7526183cfd
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user