arm64: Revert L1_CACHE_SHIFT back to 6 (64-byte cache line size)
Catalin Marinas
maintainerv3 cover arm64: Revert L1_CACHE_SHIFT back to 6 (64-byte cache line size)
Hi,
The previous version of this patch [1] didn't make it into 4.17 because of the (compile-time) conflicts with the generic dma-direct.h changes. I'm reposting it for 4.18 with some minor changes:
- phys_to_dma()/dma_to_phys() now gained underscores to match the generic dma-direct.h implementation
- the patch is split in three to make the changes clearer to the reviewers
If at some point in the future the generic swiotlb code gain non-choerent DMA awareness, the last patch in the series could be refactored. In the meantime, the simplest, non-intrusive approach is to select ARCH_HAS_PHYS_TO_DMA on arm64 and force bounce buffering through an arch-specific dma_capable() implementation.
Thanks,
Catalin
[1] http://lkml.kernel.org/r/20180228184720.25467-1-catalin.marinas at arm.com
Catalin Marinas (3):
Revert "arm64: Increase the max granular size"
arm64: Increase ARCH_DMA_MINALIGN to 128
arm64: Force swiotlb bounce buffering for non-coherent DMA with large
CWG
arch/arm64/Kconfig | 1 + arch/arm64/include/asm/cache.h | 6 +++--- arch/arm64/include/asm/dma-direct.h | 43 +++++++++++++++++++++++++++++++++++++ arch/arm64/kernel/cpufeature.c | 9 ++------ arch/arm64/mm/dma-mapping.c | 17 +++++++++++++++ arch/arm64/mm/init.c | 3 ++- 6 files changed, 68 insertions(+), 11 deletions(-) create mode 100644 arch/arm64/include/asm/dma-direct.h
Catalin Marinas
maintainerPATCH v3 1/3 Revert "arm64: Increase the max granular size"
This reverts commit 97303480753e48fb313dc0e15daaf11b0451cdb8.
Commit 97303480753e ("arm64: Increase the max granular size") increased the cache line size to 128 to match Cavium ThunderX, apparently for some performance benefit which could not be confirmed. This change, however, has an impact on the network packet allocation in certain circumstances, requiring slightly over a 4K page with a significant performance degradation. The patch reverts L1_CACHE_SHIFT back to 6 (64-byte cache line).
--- arch/arm64/include/asm/cache.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/include/asm/cache.h +1 -1
@@ -33,7 +33,7 @@#define ICACHE_POLICY_VIPT 2#define ICACHE_POLICY_PIPT 3 -#define L1_CACHE_SHIFT 7 +#define L1_CACHE_SHIFT (6)#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)/*
Catalin Marinas
maintainerPATCH v3 2/3 arm64: Increase ARCH_DMA_MINALIGN to 128
In reply to Catalin MarinasThis patch increases the ARCH_DMA_MINALIGN to 128 so that it covers the currently known Cache Writeback Granule (CTR_EL0.CWG) on arm64 and moves the fallback in cache_line_size() from L1_CACHE_BYTES to this constant.
--- arch/arm64/include/asm/cache.h | 4 ++-- arch/arm64/kernel/cpufeature.c | 9 ++------- 2 files changed, 4 insertions(+), 9 deletions(-)
arch/arm64/include/asm/cache.h +2 -2
@@ -43,7 +43,7 @@* cache before the transfer is done, causing old data to be seen by * the CPU. */ -#define ARCH_DMA_MINALIGN L1_CACHE_BYTES +#define ARCH_DMA_MINALIGN (128)#ifndef __ASSEMBLY__
@@ -77,7 +77,7 @@ static inline u32 cache_type_cwg(void)static inline int cache_line_size (void ) {u32 cwg =cache_type_cwg (); -return cwg ?4 << cwg :L1_CACHE_BYTES ; +return cwg ?4 << cwg :ARCH_DMA_MINALIGN ; }#endif /* __ASSEMBLY__ */
arch/arm64/kernel/cpufeature.c +2 -7
@@ -1606,7 +1606,6 @@ static void __init setup_system_capabilities(void)void __init setup_cpu_features (void ) {u32 cwg; -int cls;setup_system_capabilities ();mark_const_caps_ready ();
@@ -1627,13 +1626,9 @@ void __init setup_cpu_features(void)* Check for sane CTR_EL0.CWG value. */ cwg =cache_type_cwg (); - cls =cache_line_size ();if (!cwg) -pr_warn ("No Cache Writeback Granule information, assuming cache line size %d\n" , - cls); -if (L1_CACHE_BYTES < cls) -pr_warn ("L1_CACHE_BYTES smaller than the Cache Writeback Granule (%d < %d)\n" , -L1_CACHE_BYTES , cls); +pr_warn ("No Cache Writeback Granule information, assuming %d\n" , +ARCH_DMA_MINALIGN ); } static bool __maybe_unused
Catalin Marinas
maintainerPATCH v3 3/3 arm64: Force swiotlb bounce buffering for non-coherent DMA with large CWG
In reply to Catalin MarinasOn systems with a Cache Writeback Granule (CTR_EL0.CWG) greater than ARCH_DMA_MINALIGN, DMA cache maintenance on sub-CWG ranges is not safe, leading to data corruption. If such configuration is detected, the kernel will force swiotlb bounce buffering for all non-coherent devices.
--- arch/arm64/Kconfig | 1 + arch/arm64/include/asm/dma-direct.h | 43 +++++++++++++++++++++++++++++++++++++ arch/arm64/mm/dma-mapping.c | 17 +++++++++++++++ arch/arm64/mm/init.c | 3 ++- 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/include/asm/dma-direct.h
arch/arm64/Kconfig +1 -0
@@ -17,6 +17,7 @@ config ARM64 select ARCH_HAS_GIGANTIC_PAGE if (MEMORY_ISOLATION && COMPACTION) || CMA select ARCH_HAS_KCOV select ARCH_HAS_MEMBARRIER_SYNC_CORE + select ARCH_HAS_PHYS_TO_DMA select ARCH_HAS_SET_MEMORY select ARCH_HAS_SG_CHAIN select ARCH_HAS_STRICT_KERNEL_RWX
arch/arm64/include/asm/dma-direct.h new file +43 -0
43 lines not on this page · raw message
arch/arm64/mm/dma-mapping.c +17 -0
@@ -33,6 +33,7 @@#include <asm/cacheflush.h> static int swiotlb__ro_after_init ; +DEFINE_STATIC_KEY_FALSE (swiotlb_noncoherent_bounce);static pgprot_t __get_dma_pgprot (unsigned long attrs,pgprot_t prot,bool coherent)
@@ -504,6 +505,14 @@ static int __init arm64_dma_init(void) max_pfn > (arm64_dma_phys_limit >> PAGE_SHIFT)) swiotlb =1 ; +if (WARN_TAINT (ARCH_DMA_MINALIGN <cache_line_size (), +TAINT_CPU_OUT_OF_SPEC , +"ARCH_DMA_MINALIGN smaller than CTR_EL0.CWG (%d < %d)" , +ARCH_DMA_MINALIGN ,cache_line_size ())) { + swiotlb =1 ; +static_branch_enable (&swiotlb_noncoherent_bounce); + } +return atomic_pool_init (); }arch_initcall (arm64_dma_init);
@@ -882,6 +891,14 @@ static void __iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,void arch_setup_dma_ops (struct device *dev,u64 dma_base,u64 size,const struct iommu_ops *iommu,bool coherent) { +/* +* Enable swiotlb for buffer bouncing if ARCH_DMA_MINALIGN < CWG. +* dma_capable() forces the actual bounce if the device is +* non-coherent. +*/ +if (static_branch_unlikely (&swiotlb_noncoherent_bounce) && !coherent) + iommu =NULL ; +if (!dev->dma_ops) dev->dma_ops = &arm64_swiotlb_dma_ops;
arch/arm64/mm/init.c +2 -1
@@ -586,7 +586,8 @@ static void __init free_unused_memmap(void)void __init mem_init (void ) {if (swiotlb_force ==SWIOTLB_FORCE || - max_pfn > (arm64_dma_phys_limit >>PAGE_SHIFT )) + max_pfn > (arm64_dma_phys_limit >>PAGE_SHIFT ) || +ARCH_DMA_MINALIGN <cache_line_size ())swiotlb_init (1 );else swiotlb_force =SWIOTLB_NO_FORCE ;
PATCH v3 3/3 arm64: Force swiotlb bounce buffering for non-coherent DMA with large CWG
Quoted 4 lines · Catalin Marinas
On systems with a Cache Writeback Granule (CTR_EL0.CWG) greater than
ARCH_DMA_MINALIGN, DMA cache maintenance on sub-CWG ranges is not safe, leading to data corruption. If such configuration is detected, the kernel will force swiotlb bounce buffering for all non-coherent devices.
Per the previous discussion I understand that so far this is a purely theoretical condition. Given that I'd rather avoid commiting this patch and just refuse too boot in this case.
In a merge window or two I plan to have a noncoherent flag in struct device, at which point we can handle this entirely in common code.
Catalin Marinas
maintainerPATCH v3 3/3 arm64: Force swiotlb bounce buffering for non-coherent DMA with large CWG
Quoted 8 lines · Christoph Hellwig
Quoted 4 lines · Catalin Marinas
On systems with a Cache Writeback Granule (CTR_EL0.CWG) greater than
ARCH_DMA_MINALIGN, DMA cache maintenance on sub-CWG ranges is not safe, leading to data corruption. If such configuration is detected, the kernel will force swiotlb bounce buffering for all non-coherent devices.Per the previous discussion I understand that so far this is a purely theoretical condition.
That's what we think, at least for publicly available hardware.
Quoted 2 lines
Given that I'd rather avoid commiting this patch and just refuse too boot in this case.
I'll keep it to a WARN_TAINT() for now. Given that the warn triggers only when cache_line_size() > ARCH_DMA_MINALIGN and we keep this constant unchanged (128), it shouldn't be much different from our current assumptions and no-one complained of DMA corruption so far.
Quoted 2 lines
In a merge window or two I plan to have a noncoherent flag in struct device, at which point we can handle this entirely in common code.
Sounds ok, looking forward to this.
Thanks.
Signature · 1 line
Catalin