linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/3] dma: support DMA zone starting above 4GB
@ 2024-07-29 10:51 Baruch Siach
  2024-07-29 10:51 ` [PATCH v3 1/3] dma-mapping: improve DMA zone selection Baruch Siach
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Baruch Siach @ 2024-07-29 10:51 UTC (permalink / raw)
  To: Christoph Hellwig, Marek Szyprowski, Catalin Marinas, Will Deacon
  Cc: Baruch Siach, Robin Murphy, iommu, linux-arm-kernel, linux-kernel,
	linuxppc-dev, linux-s390, Petr Tesařík, Ramon Fried,
	Elad Nachman

DMA zones code assumes that DMA lower limit is zero. When there is no RAM 
below 4GB, arm64 platform code sets DMA/DMA32 zone limits to cover the entire 
RAM[0].

My target platform has RAM starting at 32GB. Devices with 30-bit DMA mask are 
mapped to 1GB at the bottom of RAM, between 32GB - 33GB. DMA zone over the 
entire RAM breaks DMA allocation for these devices.

In response to a previous RFC hack[1] Catalin Marinas suggested to add a
separate offset value as base address for the DMA zone, and then refined the 
suggestion to use start of RAM[3]. This RFC series attempts to implement that 
suggestion.

With this series applied, the DMA zone covers the right RAM range for my 
platform.

v3:

  * Rebase on v6.11-rc1.

  * Drop zone_dma_base. Use memblock_start_of_DRAM() instead.

  * Drop DT patches. Low DMA range limit no longer needed.

  * Add patch to improve dma_direct_optimal_gfp_mask() heuristics as Catalin 
    suggested.

RFC v2:

  * Add patch from Catalin[2] changing zone_dma_bits to zone_dma_limit to 
    simplify subsequent patches

  * Test on real hardware

RFC v1: https://lore.kernel.org/all/cover.1703683642.git.baruch@tkos.co.il/

[0] See commit 791ab8b2e3db ("arm64: Ignore any DMA offsets in the 
    max_zone_phys() calculation")

[1] https://lore.kernel.org/all/9af8a19c3398e7dc09cfc1fbafed98d795d9f83e.1699464622.git.baruch@tkos.co.il/

[2] https://lore.kernel.org/all/ZZ2HnHJV3gdzu1Aj@arm.com/

[3] https://lore.kernel.org/all/ZnH-VU2iz9Q2KLbr@arm.com/

Baruch Siach (2):
  dma-mapping: improve DMA zone selection
  dma-direct: use RAM start to offset zone_dma_limit

Catalin Marinas (1):
  dma-mapping: replace zone_dma_bits by zone_dma_limit

 arch/arm64/mm/init.c       | 34 +++++++++++++---------------------
 arch/powerpc/mm/mem.c      |  9 ++++-----
 arch/s390/mm/init.c        |  2 +-
 include/linux/dma-direct.h |  2 +-
 kernel/dma/direct.c        | 15 ++++++++-------
 kernel/dma/pool.c          |  3 ++-
 kernel/dma/swiotlb.c       |  4 ++--
 7 files changed, 31 insertions(+), 38 deletions(-)

-- 
2.43.0



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 1/3] dma-mapping: improve DMA zone selection
  2024-07-29 10:51 [PATCH v3 0/3] dma: support DMA zone starting above 4GB Baruch Siach
@ 2024-07-29 10:51 ` Baruch Siach
  2024-07-29 10:51 ` [PATCH v3 2/3] dma-mapping: replace zone_dma_bits by zone_dma_limit Baruch Siach
  2024-07-29 10:51 ` [PATCH v3 3/3] dma-direct: use RAM start to offset zone_dma_limit Baruch Siach
  2 siblings, 0 replies; 12+ messages in thread
From: Baruch Siach @ 2024-07-29 10:51 UTC (permalink / raw)
  To: Christoph Hellwig, Marek Szyprowski, Catalin Marinas, Will Deacon
  Cc: Baruch Siach, Robin Murphy, iommu, linux-arm-kernel, linux-kernel,
	linuxppc-dev, linux-s390, Petr Tesařík, Ramon Fried,
	Elad Nachman

When device DMA limit does not fit in DMA32 zone it should use DMA zone,
even when DMA zone is stricter than needed.

Same goes for devices that can't allocate from the entire normal zone.
Limit to DMA32 in that case.

Reported-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
---
 kernel/dma/direct.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 4480a3cd92e0..3b4be4ca3b08 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -4,7 +4,7 @@
  *
  * DMA operations that map physical memory directly without using an IOMMU.
  */
-#include <linux/memblock.h> /* for max_pfn */
+#include <linux/memblock.h>
 #include <linux/export.h>
 #include <linux/mm.h>
 #include <linux/dma-map-ops.h>
@@ -59,9 +59,9 @@ static gfp_t dma_direct_optimal_gfp_mask(struct device *dev, u64 *phys_limit)
 	 * zones.
 	 */
 	*phys_limit = dma_to_phys(dev, dma_limit);
-	if (*phys_limit <= DMA_BIT_MASK(zone_dma_bits))
+	if (*phys_limit < DMA_BIT_MASK(32))
 		return GFP_DMA;
-	if (*phys_limit <= DMA_BIT_MASK(32))
+	if (*phys_limit < memblock_end_of_DRAM())
 		return GFP_DMA32;
 	return 0;
 }
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 2/3] dma-mapping: replace zone_dma_bits by zone_dma_limit
  2024-07-29 10:51 [PATCH v3 0/3] dma: support DMA zone starting above 4GB Baruch Siach
  2024-07-29 10:51 ` [PATCH v3 1/3] dma-mapping: improve DMA zone selection Baruch Siach
@ 2024-07-29 10:51 ` Baruch Siach
  2024-07-29 20:20   ` kernel test robot
  2024-07-31 17:26   ` Catalin Marinas
  2024-07-29 10:51 ` [PATCH v3 3/3] dma-direct: use RAM start to offset zone_dma_limit Baruch Siach
  2 siblings, 2 replies; 12+ messages in thread
From: Baruch Siach @ 2024-07-29 10:51 UTC (permalink / raw)
  To: Christoph Hellwig, Marek Szyprowski, Catalin Marinas, Will Deacon
  Cc: Baruch Siach, Robin Murphy, iommu, linux-arm-kernel, linux-kernel,
	linuxppc-dev, linux-s390, Petr Tesařík, Ramon Fried,
	Elad Nachman

From: Catalin Marinas <catalin.marinas@arm.com>

Hardware DMA limit might not be power of 2. When RAM range starts above
0, say 4GB, DMA limit of 30 bits should end at 5GB. A single high bit
can not encode this limit.

Use direct phys_addr_t limit address for DMA zone limit.

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
---
 arch/arm64/mm/init.c       | 34 +++++++++++++---------------------
 arch/powerpc/mm/mem.c      |  9 ++++-----
 arch/s390/mm/init.c        |  2 +-
 include/linux/dma-direct.h |  2 +-
 kernel/dma/direct.c        |  4 ++--
 kernel/dma/pool.c          |  2 +-
 kernel/dma/swiotlb.c       |  4 ++--
 7 files changed, 24 insertions(+), 33 deletions(-)

diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 9b5ab6818f7f..870fd967c610 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -114,36 +114,28 @@ static void __init arch_reserve_crashkernel(void)
 				    low_size, high);
 }
 
-/*
- * Return the maximum physical address for a zone accessible by the given bits
- * limit. If DRAM starts above 32-bit, expand the zone to the maximum
- * available memory, otherwise cap it at 32-bit.
- */
-static phys_addr_t __init max_zone_phys(unsigned int zone_bits)
+static phys_addr_t __init max_zone_phys(phys_addr_t zone_limit)
 {
-	phys_addr_t zone_mask = DMA_BIT_MASK(zone_bits);
-	phys_addr_t phys_start = memblock_start_of_DRAM();
-
-	if (phys_start > U32_MAX)
-		zone_mask = PHYS_ADDR_MAX;
-	else if (phys_start > zone_mask)
-		zone_mask = U32_MAX;
+	/* We have RAM in low 32-bit area, keep DMA zone there */
+	if (memblock_start_of_DRAM() < U32_MAX)
+		zone_limit = min(U32_MAX, zone_limit);
 
-	return min(zone_mask, memblock_end_of_DRAM() - 1) + 1;
+	return min(zone_limit, memblock_end_of_DRAM() - 1) + 1;
 }
 
 static void __init zone_sizes_init(void)
 {
 	unsigned long max_zone_pfns[MAX_NR_ZONES]  = {0};
-	unsigned int __maybe_unused acpi_zone_dma_bits;
-	unsigned int __maybe_unused dt_zone_dma_bits;
-	phys_addr_t __maybe_unused dma32_phys_limit = max_zone_phys(32);
+	phys_addr_t __maybe_unused acpi_zone_dma_limit;
+	phys_addr_t __maybe_unused dt_zone_dma_limit;
+	phys_addr_t __maybe_unused dma32_phys_limit =
+		max_zone_phys(DMA_BIT_MASK(32));
 
 #ifdef CONFIG_ZONE_DMA
-	acpi_zone_dma_bits = fls64(acpi_iort_dma_get_max_cpu_address());
-	dt_zone_dma_bits = fls64(of_dma_get_max_cpu_address(NULL));
-	zone_dma_bits = min3(32U, dt_zone_dma_bits, acpi_zone_dma_bits);
-	arm64_dma_phys_limit = max_zone_phys(zone_dma_bits);
+	acpi_zone_dma_limit = acpi_iort_dma_get_max_cpu_address();
+	dt_zone_dma_limit = of_dma_get_max_cpu_address(NULL);
+	zone_dma_limit = min(dt_zone_dma_limit, acpi_zone_dma_limit);
+	arm64_dma_phys_limit = max_zone_phys(zone_dma_limit);
 	max_zone_pfns[ZONE_DMA] = PFN_DOWN(arm64_dma_phys_limit);
 #endif
 #ifdef CONFIG_ZONE_DMA32
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index d325217ab201..342c006cc1b8 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -216,7 +216,7 @@ static int __init mark_nonram_nosave(void)
  * everything else. GFP_DMA32 page allocations automatically fall back to
  * ZONE_DMA.
  *
- * By using 31-bit unconditionally, we can exploit zone_dma_bits to inform the
+ * By using 31-bit unconditionally, we can exploit zone_dma_limit to inform the
  * generic DMA mapping code.  32-bit only devices (if not handled by an IOMMU
  * anyway) will take a first dip into ZONE_NORMAL and get otherwise served by
  * ZONE_DMA.
@@ -252,13 +252,12 @@ void __init paging_init(void)
 	 * powerbooks.
 	 */
 	if (IS_ENABLED(CONFIG_PPC32))
-		zone_dma_bits = 30;
+		zone_dma_limit = DMA_BIT_MASK(30);
 	else
-		zone_dma_bits = 31;
+		zone_dma_limit = DMA_BIT_MASK(31);
 
 #ifdef CONFIG_ZONE_DMA
-	max_zone_pfns[ZONE_DMA]	= min(max_low_pfn,
-				      1UL << (zone_dma_bits - PAGE_SHIFT));
+	max_zone_pfns[ZONE_DMA]	= min(max_low_pfn, zone_dma_limit >> PAGE_SHIFT);
 #endif
 	max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
 #ifdef CONFIG_HIGHMEM
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index ddcd39ef4346..91fc2b91adfc 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -97,7 +97,7 @@ void __init paging_init(void)
 
 	vmem_map_init();
 	sparse_init();
-	zone_dma_bits = 31;
+	zone_dma_limit = DMA_BIT_MASK(31);
 	memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
 	max_zone_pfns[ZONE_DMA] = virt_to_pfn(MAX_DMA_ADDRESS);
 	max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
diff --git a/include/linux/dma-direct.h b/include/linux/dma-direct.h
index edbe13d00776..98b7d8015043 100644
--- a/include/linux/dma-direct.h
+++ b/include/linux/dma-direct.h
@@ -12,7 +12,7 @@
 #include <linux/mem_encrypt.h>
 #include <linux/swiotlb.h>
 
-extern unsigned int zone_dma_bits;
+extern phys_addr_t zone_dma_limit;
 
 /*
  * Record the mapping of CPU physical to DMA addresses for a given region.
diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 3b4be4ca3b08..3dbc0b89d6fb 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -20,7 +20,7 @@
  * it for entirely different regions. In that case the arch code needs to
  * override the variable below for dma-direct to work properly.
  */
-unsigned int zone_dma_bits __ro_after_init = 24;
+phys_addr_t zone_dma_limit __ro_after_init = DMA_BIT_MASK(24);
 
 static inline dma_addr_t phys_to_dma_direct(struct device *dev,
 		phys_addr_t phys)
@@ -580,7 +580,7 @@ int dma_direct_supported(struct device *dev, u64 mask)
 	 * part of the check.
 	 */
 	if (IS_ENABLED(CONFIG_ZONE_DMA))
-		min_mask = min_t(u64, min_mask, DMA_BIT_MASK(zone_dma_bits));
+		min_mask = min_t(u64, min_mask, zone_dma_limit);
 	return mask >= phys_to_dma_unencrypted(dev, min_mask);
 }
 
diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c
index d10613eb0f63..410a7b40e496 100644
--- a/kernel/dma/pool.c
+++ b/kernel/dma/pool.c
@@ -70,7 +70,7 @@ static bool cma_in_zone(gfp_t gfp)
 	/* CMA can't cross zone boundaries, see cma_activate_area() */
 	end = cma_get_base(cma) + size - 1;
 	if (IS_ENABLED(CONFIG_ZONE_DMA) && (gfp & GFP_DMA))
-		return end <= DMA_BIT_MASK(zone_dma_bits);
+		return end <= zone_dma_limit;
 	if (IS_ENABLED(CONFIG_ZONE_DMA32) && (gfp & GFP_DMA32))
 		return end <= DMA_BIT_MASK(32);
 	return true;
diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c
index df68d29740a0..dfd83e5ee0b3 100644
--- a/kernel/dma/swiotlb.c
+++ b/kernel/dma/swiotlb.c
@@ -450,7 +450,7 @@ int swiotlb_init_late(size_t size, gfp_t gfp_mask,
 	if (!remap)
 		io_tlb_default_mem.can_grow = true;
 	if (IS_ENABLED(CONFIG_ZONE_DMA) && (gfp_mask & __GFP_DMA))
-		io_tlb_default_mem.phys_limit = DMA_BIT_MASK(zone_dma_bits);
+		io_tlb_default_mem.phys_limit = zone_dma_limit;
 	else if (IS_ENABLED(CONFIG_ZONE_DMA32) && (gfp_mask & __GFP_DMA32))
 		io_tlb_default_mem.phys_limit = DMA_BIT_MASK(32);
 	else
@@ -629,7 +629,7 @@ static struct page *swiotlb_alloc_tlb(struct device *dev, size_t bytes,
 	}
 
 	gfp &= ~GFP_ZONEMASK;
-	if (phys_limit <= DMA_BIT_MASK(zone_dma_bits))
+	if (phys_limit <= zone_dma_limit)
 		gfp |= __GFP_DMA;
 	else if (phys_limit <= DMA_BIT_MASK(32))
 		gfp |= __GFP_DMA32;
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 3/3] dma-direct: use RAM start to offset zone_dma_limit
  2024-07-29 10:51 [PATCH v3 0/3] dma: support DMA zone starting above 4GB Baruch Siach
  2024-07-29 10:51 ` [PATCH v3 1/3] dma-mapping: improve DMA zone selection Baruch Siach
  2024-07-29 10:51 ` [PATCH v3 2/3] dma-mapping: replace zone_dma_bits by zone_dma_limit Baruch Siach
@ 2024-07-29 10:51 ` Baruch Siach
  2024-07-31 17:33   ` Catalin Marinas
  2 siblings, 1 reply; 12+ messages in thread
From: Baruch Siach @ 2024-07-29 10:51 UTC (permalink / raw)
  To: Christoph Hellwig, Marek Szyprowski, Catalin Marinas, Will Deacon
  Cc: Baruch Siach, Robin Murphy, iommu, linux-arm-kernel, linux-kernel,
	linuxppc-dev, linux-s390, Petr Tesařík, Ramon Fried,
	Elad Nachman

Current code using zone_dma_limit assume that all address range below
limit is suitable for DMA. For some existing platforms this assumption
is not correct. DMA range might have non zero lower limit.

Commit 791ab8b2e3db ("arm64: Ignore any DMA offsets in the
max_zone_phys() calculation") made DMA/DMA32 zones span the entire RAM
when RAM starts above 32-bits. This breaks hardware with DMA area that
start above 32-bits. But the commit log says that "we haven't noticed
any such hardware". It turns out that such hardware does exist.

One such platform has RAM starting at 32GB with an internal bus that has
the following DMA limits:

  #address-cells = <2>;
  #size-cells = <2>;
  dma-ranges = <0x00 0xc0000000 0x08 0x00000000 0x00 0x40000000>;

Devices under this bus can see 1GB of DMA range between 3GB-4GB in each
device address space. This range is mapped to CPU memory at 32GB-33GB.
With current code DMA allocations for devices under this bus are not
limited to DMA area, leading to run-time allocation failure.

Add start of RAM address to zone_dma_limit to make DMA allocation for
constrained devices possible.

The result is DMA zone that properly reflects the hardware constraints
as follows:

[    0.000000] Zone ranges:
[    0.000000]   DMA      [mem 0x0000000800000000-0x000000083fffffff]
[    0.000000]   DMA32    empty
[    0.000000]   Normal   [mem 0x0000000840000000-0x0000000bffffffff]

Rename the dma_direct_supported() local 'min_mask' variable to better
describe its use as limit.

Suggested-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
---
 kernel/dma/direct.c  | 7 ++++---
 kernel/dma/pool.c    | 3 ++-
 kernel/dma/swiotlb.c | 4 ++--
 3 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 3dbc0b89d6fb..bd7972d3b101 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -563,7 +563,7 @@ int dma_direct_mmap(struct device *dev, struct vm_area_struct *vma,
 
 int dma_direct_supported(struct device *dev, u64 mask)
 {
-	u64 min_mask = (max_pfn - 1) << PAGE_SHIFT;
+	u64 min_limit = (max_pfn - 1) << PAGE_SHIFT;
 
 	/*
 	 * Because 32-bit DMA masks are so common we expect every architecture
@@ -580,8 +580,9 @@ int dma_direct_supported(struct device *dev, u64 mask)
 	 * part of the check.
 	 */
 	if (IS_ENABLED(CONFIG_ZONE_DMA))
-		min_mask = min_t(u64, min_mask, zone_dma_limit);
-	return mask >= phys_to_dma_unencrypted(dev, min_mask);
+		min_limit = min_t(u64, min_limit,
+				memblock_start_of_DRAM() + zone_dma_limit);
+	return mask >= phys_to_dma_unencrypted(dev, min_limit);
 }
 
 /*
diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c
index 410a7b40e496..ded3d841c88c 100644
--- a/kernel/dma/pool.c
+++ b/kernel/dma/pool.c
@@ -12,6 +12,7 @@
 #include <linux/set_memory.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
+#include <linux/memblock.h>
 
 static struct gen_pool *atomic_pool_dma __ro_after_init;
 static unsigned long pool_size_dma;
@@ -70,7 +71,7 @@ static bool cma_in_zone(gfp_t gfp)
 	/* CMA can't cross zone boundaries, see cma_activate_area() */
 	end = cma_get_base(cma) + size - 1;
 	if (IS_ENABLED(CONFIG_ZONE_DMA) && (gfp & GFP_DMA))
-		return end <= zone_dma_limit;
+		return end <= memblock_start_of_DRAM() + zone_dma_limit;
 	if (IS_ENABLED(CONFIG_ZONE_DMA32) && (gfp & GFP_DMA32))
 		return end <= DMA_BIT_MASK(32);
 	return true;
diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c
index dfd83e5ee0b3..2813eeb8b375 100644
--- a/kernel/dma/swiotlb.c
+++ b/kernel/dma/swiotlb.c
@@ -450,7 +450,7 @@ int swiotlb_init_late(size_t size, gfp_t gfp_mask,
 	if (!remap)
 		io_tlb_default_mem.can_grow = true;
 	if (IS_ENABLED(CONFIG_ZONE_DMA) && (gfp_mask & __GFP_DMA))
-		io_tlb_default_mem.phys_limit = zone_dma_limit;
+		io_tlb_default_mem.phys_limit = memblock_start_of_DRAM() + zone_dma_limit;
 	else if (IS_ENABLED(CONFIG_ZONE_DMA32) && (gfp_mask & __GFP_DMA32))
 		io_tlb_default_mem.phys_limit = DMA_BIT_MASK(32);
 	else
@@ -629,7 +629,7 @@ static struct page *swiotlb_alloc_tlb(struct device *dev, size_t bytes,
 	}
 
 	gfp &= ~GFP_ZONEMASK;
-	if (phys_limit <= zone_dma_limit)
+	if (phys_limit <= memblock_start_of_DRAM() + zone_dma_limit)
 		gfp |= __GFP_DMA;
 	else if (phys_limit <= DMA_BIT_MASK(32))
 		gfp |= __GFP_DMA32;
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 2/3] dma-mapping: replace zone_dma_bits by zone_dma_limit
  2024-07-29 10:51 ` [PATCH v3 2/3] dma-mapping: replace zone_dma_bits by zone_dma_limit Baruch Siach
@ 2024-07-29 20:20   ` kernel test robot
  2024-07-30  2:12     ` Nathan Chancellor
  2024-07-31 17:26   ` Catalin Marinas
  1 sibling, 1 reply; 12+ messages in thread
From: kernel test robot @ 2024-07-29 20:20 UTC (permalink / raw)
  To: Baruch Siach, Christoph Hellwig, Marek Szyprowski,
	Catalin Marinas, Will Deacon
  Cc: llvm, oe-kbuild-all, linux-s390, Baruch Siach, Ramon Fried,
	Petr Tesařík, Robin Murphy, linux-kernel, iommu,
	Elad Nachman, linuxppc-dev, linux-arm-kernel

Hi Baruch,

kernel test robot noticed the following build warnings:

[auto build test WARNING on arm64/for-next/core]
[also build test WARNING on powerpc/next powerpc/fixes s390/features linus/master v6.11-rc1 next-20240729]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Baruch-Siach/dma-mapping-improve-DMA-zone-selection/20240729-211018
base:   https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/core
patch link:    https://lore.kernel.org/r/053fa4806a2c63efcde80caca473a8b670a2701c.1722249878.git.baruch%40tkos.co.il
patch subject: [PATCH v3 2/3] dma-mapping: replace zone_dma_bits by zone_dma_limit
config: arm-allnoconfig (https://download.01.org/0day-ci/archive/20240730/202407300338.oaUo6jtB-lkp@intel.com/config)
compiler: clang version 20.0.0git (https://github.com/llvm/llvm-project ccae7b461be339e717d02f99ac857cf0bc7d17fc)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240730/202407300338.oaUo6jtB-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202407300338.oaUo6jtB-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from kernel/dma/direct.c:7:
   In file included from include/linux/memblock.h:12:
   In file included from include/linux/mm.h:2253:
   include/linux/vmstat.h:514:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
     514 |         return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
         |                               ~~~~~~~~~~~ ^ ~~~
>> kernel/dma/direct.c:23:46: warning: implicit conversion from 'unsigned long long' to 'phys_addr_t' (aka 'unsigned int') changes value from 18446744073709551615 to 4294967295 [-Wconstant-conversion]
      23 | phys_addr_t zone_dma_limit __ro_after_init = DMA_BIT_MASK(24);
         |             ~~~~~~~~~~~~~~                   ^~~~~~~~~~~~~~~~
   include/linux/dma-mapping.h:77:40: note: expanded from macro 'DMA_BIT_MASK'
      77 | #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
         |                                        ^~~~~
   2 warnings generated.


vim +23 kernel/dma/direct.c

   > 7	#include <linux/memblock.h>
     8	#include <linux/export.h>
     9	#include <linux/mm.h>
    10	#include <linux/dma-map-ops.h>
    11	#include <linux/scatterlist.h>
    12	#include <linux/pfn.h>
    13	#include <linux/vmalloc.h>
    14	#include <linux/set_memory.h>
    15	#include <linux/slab.h>
    16	#include "direct.h"
    17	
    18	/*
    19	 * Most architectures use ZONE_DMA for the first 16 Megabytes, but some use
    20	 * it for entirely different regions. In that case the arch code needs to
    21	 * override the variable below for dma-direct to work properly.
    22	 */
  > 23	phys_addr_t zone_dma_limit __ro_after_init = DMA_BIT_MASK(24);
    24	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 2/3] dma-mapping: replace zone_dma_bits by zone_dma_limit
  2024-07-29 20:20   ` kernel test robot
@ 2024-07-30  2:12     ` Nathan Chancellor
  2024-07-30 15:34       ` Christoph Hellwig
  0 siblings, 1 reply; 12+ messages in thread
From: Nathan Chancellor @ 2024-07-30  2:12 UTC (permalink / raw)
  To: kernel test robot
  Cc: Baruch Siach, Christoph Hellwig, Marek Szyprowski,
	Catalin Marinas, Will Deacon, llvm, oe-kbuild-all, linux-s390,
	Ramon Fried, Petr Tesařík, Robin Murphy, linux-kernel,
	iommu, Elad Nachman, linuxppc-dev, linux-arm-kernel

On Tue, Jul 30, 2024 at 04:20:51AM +0800, kernel test robot wrote:
> Hi Baruch,
> 
> kernel test robot noticed the following build warnings:
> 
> [auto build test WARNING on arm64/for-next/core]
> [also build test WARNING on powerpc/next powerpc/fixes s390/features linus/master v6.11-rc1 next-20240729]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
> 
> url:    https://github.com/intel-lab-lkp/linux/commits/Baruch-Siach/dma-mapping-improve-DMA-zone-selection/20240729-211018
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/core
> patch link:    https://lore.kernel.org/r/053fa4806a2c63efcde80caca473a8b670a2701c.1722249878.git.baruch%40tkos.co.il
> patch subject: [PATCH v3 2/3] dma-mapping: replace zone_dma_bits by zone_dma_limit
> config: arm-allnoconfig (https://download.01.org/0day-ci/archive/20240730/202407300338.oaUo6jtB-lkp@intel.com/config)
> compiler: clang version 20.0.0git (https://github.com/llvm/llvm-project ccae7b461be339e717d02f99ac857cf0bc7d17fc)
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240730/202407300338.oaUo6jtB-lkp@intel.com/reproduce)
> 
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202407300338.oaUo6jtB-lkp@intel.com/
> 
> All warnings (new ones prefixed by >>):
> 
>    In file included from kernel/dma/direct.c:7:
>    In file included from include/linux/memblock.h:12:
>    In file included from include/linux/mm.h:2253:
>    include/linux/vmstat.h:514:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
>      514 |         return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
>          |                               ~~~~~~~~~~~ ^ ~~~
> >> kernel/dma/direct.c:23:46: warning: implicit conversion from 'unsigned long long' to 'phys_addr_t' (aka 'unsigned int') changes value from 18446744073709551615 to 4294967295 [-Wconstant-conversion]
>       23 | phys_addr_t zone_dma_limit __ro_after_init = DMA_BIT_MASK(24);
>          |             ~~~~~~~~~~~~~~                   ^~~~~~~~~~~~~~~~
>    include/linux/dma-mapping.h:77:40: note: expanded from macro 'DMA_BIT_MASK'
>       77 | #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
>          |                                        ^~~~~
>    2 warnings generated.

FWIW, this is likely a false positive due to an issue in Clang with the
control flow graph for global variables:

https://github.com/ClangBuiltLinux/linux/issues/92

DMA_BIT_MASK() has been the biggest offender :/ If there is any way to
refactor this code to avoid this, that would be great (as that has been
one of our longest outstanding issues and getting it fixed in the
compiler does not seem super easy at this point).

Cheers,
Nathan

> vim +23 kernel/dma/direct.c
> 
>    > 7	#include <linux/memblock.h>
>      8	#include <linux/export.h>
>      9	#include <linux/mm.h>
>     10	#include <linux/dma-map-ops.h>
>     11	#include <linux/scatterlist.h>
>     12	#include <linux/pfn.h>
>     13	#include <linux/vmalloc.h>
>     14	#include <linux/set_memory.h>
>     15	#include <linux/slab.h>
>     16	#include "direct.h"
>     17	
>     18	/*
>     19	 * Most architectures use ZONE_DMA for the first 16 Megabytes, but some use
>     20	 * it for entirely different regions. In that case the arch code needs to
>     21	 * override the variable below for dma-direct to work properly.
>     22	 */
>   > 23	phys_addr_t zone_dma_limit __ro_after_init = DMA_BIT_MASK(24);
>     24	
> 
> -- 
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki
> 


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 2/3] dma-mapping: replace zone_dma_bits by zone_dma_limit
  2024-07-30  2:12     ` Nathan Chancellor
@ 2024-07-30 15:34       ` Christoph Hellwig
  2024-08-01  1:24         ` Nathan Chancellor
  0 siblings, 1 reply; 12+ messages in thread
From: Christoph Hellwig @ 2024-07-30 15:34 UTC (permalink / raw)
  To: Nathan Chancellor
  Cc: kernel test robot, Baruch Siach, Christoph Hellwig,
	Marek Szyprowski, Catalin Marinas, Will Deacon, llvm,
	oe-kbuild-all, linux-s390, Ramon Fried, Petr Tesařík,
	Robin Murphy, linux-kernel, iommu, Elad Nachman, linuxppc-dev,
	linux-arm-kernel

On Mon, Jul 29, 2024 at 07:12:08PM -0700, Nathan Chancellor wrote:
> >          |             ~~~~~~~~~~~~~~                   ^~~~~~~~~~~~~~~~
> >    include/linux/dma-mapping.h:77:40: note: expanded from macro 'DMA_BIT_MASK'
> >       77 | #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
> >          |                                        ^~~~~
> >    2 warnings generated.
> 
> FWIW, this is likely a false positive due to an issue in Clang with the
> control flow graph for global variables:
> 
> https://github.com/ClangBuiltLinux/linux/issues/92
> 
> DMA_BIT_MASK() has been the biggest offender :/ If there is any way to
> refactor this code to avoid this, that would be great (as that has been
> one of our longest outstanding issues and getting it fixed in the
> compiler does not seem super easy at this point).

I have no idea what you'd want changed here, but I'll happily take
patches.



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 2/3] dma-mapping: replace zone_dma_bits by zone_dma_limit
  2024-07-29 10:51 ` [PATCH v3 2/3] dma-mapping: replace zone_dma_bits by zone_dma_limit Baruch Siach
  2024-07-29 20:20   ` kernel test robot
@ 2024-07-31 17:26   ` Catalin Marinas
  1 sibling, 0 replies; 12+ messages in thread
From: Catalin Marinas @ 2024-07-31 17:26 UTC (permalink / raw)
  To: Baruch Siach
  Cc: Christoph Hellwig, Marek Szyprowski, Will Deacon, Robin Murphy,
	iommu, linux-arm-kernel, linux-kernel, linuxppc-dev, linux-s390,
	Petr Tesařík, Ramon Fried, Elad Nachman

On Mon, Jul 29, 2024 at 01:51:25PM +0300, Baruch Siach wrote:
> From: Catalin Marinas <catalin.marinas@arm.com>
> 
> Hardware DMA limit might not be power of 2. When RAM range starts above
> 0, say 4GB, DMA limit of 30 bits should end at 5GB. A single high bit
> can not encode this limit.
> 
> Use direct phys_addr_t limit address for DMA zone limit.
> 
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> Signed-off-by: Baruch Siach <baruch@tkos.co.il>

You should add your Co-developed-by line, the patch evolved a bit from
initial my partial diff.

> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> index 9b5ab6818f7f..870fd967c610 100644
> --- a/arch/arm64/mm/init.c
> +++ b/arch/arm64/mm/init.c
> @@ -114,36 +114,28 @@ static void __init arch_reserve_crashkernel(void)
>  				    low_size, high);
>  }
>  
> -/*
> - * Return the maximum physical address for a zone accessible by the given bits
> - * limit. If DRAM starts above 32-bit, expand the zone to the maximum
> - * available memory, otherwise cap it at 32-bit.
> - */
> -static phys_addr_t __init max_zone_phys(unsigned int zone_bits)
> +static phys_addr_t __init max_zone_phys(phys_addr_t zone_limit)
>  {
> -	phys_addr_t zone_mask = DMA_BIT_MASK(zone_bits);
> -	phys_addr_t phys_start = memblock_start_of_DRAM();
> -
> -	if (phys_start > U32_MAX)
> -		zone_mask = PHYS_ADDR_MAX;
> -	else if (phys_start > zone_mask)
> -		zone_mask = U32_MAX;
> +	/* We have RAM in low 32-bit area, keep DMA zone there */
> +	if (memblock_start_of_DRAM() < U32_MAX)
> +		zone_limit = min(U32_MAX, zone_limit);

Does this matter anymore? Or is it to keep ZONE_DMA below (or equal to)
the ZONE_DMA32 limit?

Anyway, since this patch is about replacing zone_dma_bits with
zone_dma_limit, we should not introduce functional changes. AFAICT, we
need zone_limit to be set to memblock_end_of_DRAM() when phys_start is
above U32_MAX. You can do the functional change in a subsequent patch
once all the other refactoring has been handled.

>  
> -	return min(zone_mask, memblock_end_of_DRAM() - 1) + 1;
> +	return min(zone_limit, memblock_end_of_DRAM() - 1) + 1;
>  }
[...]
> diff --git a/include/linux/dma-direct.h b/include/linux/dma-direct.h
> index edbe13d00776..98b7d8015043 100644
> --- a/include/linux/dma-direct.h
> +++ b/include/linux/dma-direct.h
> @@ -12,7 +12,7 @@
>  #include <linux/mem_encrypt.h>
>  #include <linux/swiotlb.h>
>  
> -extern unsigned int zone_dma_bits;
> +extern phys_addr_t zone_dma_limit;
>  
>  /*
>   * Record the mapping of CPU physical to DMA addresses for a given region.
> diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
> index 3b4be4ca3b08..3dbc0b89d6fb 100644
> --- a/kernel/dma/direct.c
> +++ b/kernel/dma/direct.c
> @@ -20,7 +20,7 @@
>   * it for entirely different regions. In that case the arch code needs to
>   * override the variable below for dma-direct to work properly.
>   */
> -unsigned int zone_dma_bits __ro_after_init = 24;
> +phys_addr_t zone_dma_limit __ro_after_init = DMA_BIT_MASK(24);
>  
>  static inline dma_addr_t phys_to_dma_direct(struct device *dev,
>  		phys_addr_t phys)
> @@ -580,7 +580,7 @@ int dma_direct_supported(struct device *dev, u64 mask)
>  	 * part of the check.
>  	 */
>  	if (IS_ENABLED(CONFIG_ZONE_DMA))
> -		min_mask = min_t(u64, min_mask, DMA_BIT_MASK(zone_dma_bits));
> +		min_mask = min_t(u64, min_mask, zone_dma_limit);
>  	return mask >= phys_to_dma_unencrypted(dev, min_mask);
>  }
>  
> diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c
> index d10613eb0f63..410a7b40e496 100644
> --- a/kernel/dma/pool.c
> +++ b/kernel/dma/pool.c
> @@ -70,7 +70,7 @@ static bool cma_in_zone(gfp_t gfp)
>  	/* CMA can't cross zone boundaries, see cma_activate_area() */
>  	end = cma_get_base(cma) + size - 1;
>  	if (IS_ENABLED(CONFIG_ZONE_DMA) && (gfp & GFP_DMA))
> -		return end <= DMA_BIT_MASK(zone_dma_bits);
> +		return end <= zone_dma_limit;
>  	if (IS_ENABLED(CONFIG_ZONE_DMA32) && (gfp & GFP_DMA32))
>  		return end <= DMA_BIT_MASK(32);
>  	return true;

I haven't got to the third patch yet but with this series we can have
zone_dma_limit above DMA_BIT_MASK(32). The above function could return
false for GFP_DMA32 when 'end' is perfectly valid within ZONE_DMA (which
implies safe for GFP_DMA32).

> diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c
> index df68d29740a0..dfd83e5ee0b3 100644
> --- a/kernel/dma/swiotlb.c
> +++ b/kernel/dma/swiotlb.c
> @@ -450,7 +450,7 @@ int swiotlb_init_late(size_t size, gfp_t gfp_mask,
>  	if (!remap)
>  		io_tlb_default_mem.can_grow = true;
>  	if (IS_ENABLED(CONFIG_ZONE_DMA) && (gfp_mask & __GFP_DMA))
> -		io_tlb_default_mem.phys_limit = DMA_BIT_MASK(zone_dma_bits);
> +		io_tlb_default_mem.phys_limit = zone_dma_limit;
>  	else if (IS_ENABLED(CONFIG_ZONE_DMA32) && (gfp_mask & __GFP_DMA32))
>  		io_tlb_default_mem.phys_limit = DMA_BIT_MASK(32);
>  	else
> @@ -629,7 +629,7 @@ static struct page *swiotlb_alloc_tlb(struct device *dev, size_t bytes,
>  	}
>  
>  	gfp &= ~GFP_ZONEMASK;
> -	if (phys_limit <= DMA_BIT_MASK(zone_dma_bits))
> +	if (phys_limit <= zone_dma_limit)
>  		gfp |= __GFP_DMA;
>  	else if (phys_limit <= DMA_BIT_MASK(32))
>  		gfp |= __GFP_DMA32;

I think this has the same issue as dma_direct_optimal_gfp_mask(). If
the requested limit is strictly smaller than DMA_BIT_MASK(32) (but
potentially bigger than zone_dma_limit), we should go for __GFP_DMA
rather than __GFP_DMA32. You should probably fix this in the first patch
as well.

As above, with this series we can end up with zone_dma_limit above
DMA_BIT_MASK(32) and all these checks become confusing. Even the
swiotlb_init_late() above if called with GFP_DMA32 will set a phys_limit
that may not be accessible at all if the DRAM starts above 4GB.
Similarly, cma_in_zone() could return false with GFP_DMA32 in similar
hardware configurations.

So we either introduce a zone_dma32_limit variable and allow a 32-bit
range above the start of DRAM or sanitise these sites to make sure
passing GFP_DMA32 is safe - i.e. assume we only have ZONE_DMA if
zone_dma_limit is above 32-bit. I prefer the latter without introducing
a zone_dma32_limit.

-- 
Catalin


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 3/3] dma-direct: use RAM start to offset zone_dma_limit
  2024-07-29 10:51 ` [PATCH v3 3/3] dma-direct: use RAM start to offset zone_dma_limit Baruch Siach
@ 2024-07-31 17:33   ` Catalin Marinas
  0 siblings, 0 replies; 12+ messages in thread
From: Catalin Marinas @ 2024-07-31 17:33 UTC (permalink / raw)
  To: Baruch Siach
  Cc: Christoph Hellwig, Marek Szyprowski, Will Deacon, Robin Murphy,
	iommu, linux-arm-kernel, linux-kernel, linuxppc-dev, linux-s390,
	Petr Tesařík, Ramon Fried, Elad Nachman

On Mon, Jul 29, 2024 at 01:51:26PM +0300, Baruch Siach wrote:
> diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c
> index 410a7b40e496..ded3d841c88c 100644
> --- a/kernel/dma/pool.c
> +++ b/kernel/dma/pool.c
> @@ -12,6 +12,7 @@
>  #include <linux/set_memory.h>
>  #include <linux/slab.h>
>  #include <linux/workqueue.h>
> +#include <linux/memblock.h>
>  
>  static struct gen_pool *atomic_pool_dma __ro_after_init;
>  static unsigned long pool_size_dma;
> @@ -70,7 +71,7 @@ static bool cma_in_zone(gfp_t gfp)
>  	/* CMA can't cross zone boundaries, see cma_activate_area() */
>  	end = cma_get_base(cma) + size - 1;
>  	if (IS_ENABLED(CONFIG_ZONE_DMA) && (gfp & GFP_DMA))
> -		return end <= zone_dma_limit;
> +		return end <= memblock_start_of_DRAM() + zone_dma_limit;

I think this patch is entirely wrong. After the previous patch,
zone_dma_limit is already a physical/CPU address, not some offset or
range - of_dma_get_max_cpu_address() returns the absolute physical
address. Adding memblock_start_of_DRAM() to it does not make any sense.
It made sense when we had zone_dma_bits but since we are trying to move
away from bitmasks to absolute CPU addresses, zone_dma_limit already
includes the start of DRAM.

What problems do you see without this patch? Is it because
DMA_BIT_MASK(32) can be lower than zone_dma_limit as I mentioned on the
previous patch?

-- 
Catalin


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 2/3] dma-mapping: replace zone_dma_bits by zone_dma_limit
  2024-07-30 15:34       ` Christoph Hellwig
@ 2024-08-01  1:24         ` Nathan Chancellor
  2024-08-01 13:44           ` Christoph Hellwig
  0 siblings, 1 reply; 12+ messages in thread
From: Nathan Chancellor @ 2024-08-01  1:24 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: kernel test robot, Baruch Siach, Marek Szyprowski,
	Catalin Marinas, Will Deacon, llvm, oe-kbuild-all, linux-s390,
	Ramon Fried, Petr Tesařík, Robin Murphy, linux-kernel,
	iommu, Elad Nachman, linuxppc-dev, linux-arm-kernel

On Tue, Jul 30, 2024 at 05:34:50PM +0200, Christoph Hellwig wrote:
> On Mon, Jul 29, 2024 at 07:12:08PM -0700, Nathan Chancellor wrote:
> > >          |             ~~~~~~~~~~~~~~                   ^~~~~~~~~~~~~~~~
> > >    include/linux/dma-mapping.h:77:40: note: expanded from macro 'DMA_BIT_MASK'
> > >       77 | #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
> > >          |                                        ^~~~~
> > >    2 warnings generated.
> > 
> > FWIW, this is likely a false positive due to an issue in Clang with the
> > control flow graph for global variables:
> > 
> > https://github.com/ClangBuiltLinux/linux/issues/92
> > 
> > DMA_BIT_MASK() has been the biggest offender :/ If there is any way to
> > refactor this code to avoid this, that would be great (as that has been
> > one of our longest outstanding issues and getting it fixed in the
> > compiler does not seem super easy at this point).
> 
> I have no idea what you'd want changed here, but I'll happily take
> patches.

Unfortunately, I am not sure either... I do not see anything obviously,
so perhaps it could just be avoided with the __diag() infrastructure?

diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 3dbc0b89d6fb..b58e7eb9c8f1 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -20,7 +20,12 @@
  * it for entirely different regions. In that case the arch code needs to
  * override the variable below for dma-direct to work properly.
  */
+__diag_push();
+__diag_ignore(clang, 13, "-Wconstant-conversion",
+	      "Clang incorrectly thinks the n == 64 case in DMA_BIT_MASK() can happen here,"
+	      "which would truncate with a 32-bit phys_addr_t");
 phys_addr_t zone_dma_limit __ro_after_init = DMA_BIT_MASK(24);
+__diag_pop();
 
 static inline dma_addr_t phys_to_dma_direct(struct device *dev,
 		phys_addr_t phys)


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 2/3] dma-mapping: replace zone_dma_bits by zone_dma_limit
  2024-08-01  1:24         ` Nathan Chancellor
@ 2024-08-01 13:44           ` Christoph Hellwig
  2024-08-01 15:22             ` Nathan Chancellor
  0 siblings, 1 reply; 12+ messages in thread
From: Christoph Hellwig @ 2024-08-01 13:44 UTC (permalink / raw)
  To: Nathan Chancellor
  Cc: Christoph Hellwig, kernel test robot, Baruch Siach,
	Marek Szyprowski, Catalin Marinas, Will Deacon, llvm,
	oe-kbuild-all, linux-s390, Ramon Fried, Petr Tesařík,
	Robin Murphy, linux-kernel, iommu, Elad Nachman, linuxppc-dev,
	linux-arm-kernel

On Wed, Jul 31, 2024 at 06:24:24PM -0700, Nathan Chancellor wrote:
> Unfortunately, I am not sure either... I do not see anything obviously,
> so perhaps it could just be avoided with the __diag() infrastructure?
> 
> diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
> index 3dbc0b89d6fb..b58e7eb9c8f1 100644
> --- a/kernel/dma/direct.c
> +++ b/kernel/dma/direct.c
> @@ -20,7 +20,12 @@
>   * it for entirely different regions. In that case the arch code needs to
>   * override the variable below for dma-direct to work properly.
>   */
> +__diag_push();
> +__diag_ignore(clang, 13, "-Wconstant-conversion",
> +	      "Clang incorrectly thinks the n == 64 case in DMA_BIT_MASK() can happen here,"
> +	      "which would truncate with a 32-bit phys_addr_t");
>  phys_addr_t zone_dma_limit __ro_after_init = DMA_BIT_MASK(24);

So..  The code above is clearly wrong, as DMA_BIT_MASK always returns a
u64, and phys_addr_t can be smaller than that.  So at least in this case
the warning seems perfectly valid and the code has issues because it is
mixing different concepts.

Where do you see warnings like this upstream?



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 2/3] dma-mapping: replace zone_dma_bits by zone_dma_limit
  2024-08-01 13:44           ` Christoph Hellwig
@ 2024-08-01 15:22             ` Nathan Chancellor
  0 siblings, 0 replies; 12+ messages in thread
From: Nathan Chancellor @ 2024-08-01 15:22 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: kernel test robot, Baruch Siach, Marek Szyprowski,
	Catalin Marinas, Will Deacon, llvm, oe-kbuild-all, linux-s390,
	Ramon Fried, Petr Tesařík, Robin Murphy, linux-kernel,
	iommu, Elad Nachman, linuxppc-dev, linux-arm-kernel

On Thu, Aug 01, 2024 at 03:44:54PM +0200, Christoph Hellwig wrote:
> On Wed, Jul 31, 2024 at 06:24:24PM -0700, Nathan Chancellor wrote:
> > Unfortunately, I am not sure either... I do not see anything obviously,
> > so perhaps it could just be avoided with the __diag() infrastructure?
> > 
> > diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
> > index 3dbc0b89d6fb..b58e7eb9c8f1 100644
> > --- a/kernel/dma/direct.c
> > +++ b/kernel/dma/direct.c
> > @@ -20,7 +20,12 @@
> >   * it for entirely different regions. In that case the arch code needs to
> >   * override the variable below for dma-direct to work properly.
> >   */
> > +__diag_push();
> > +__diag_ignore(clang, 13, "-Wconstant-conversion",
> > +	      "Clang incorrectly thinks the n == 64 case in DMA_BIT_MASK() can happen here,"
> > +	      "which would truncate with a 32-bit phys_addr_t");
> >  phys_addr_t zone_dma_limit __ro_after_init = DMA_BIT_MASK(24);
> 
> So..  The code above is clearly wrong, as DMA_BIT_MASK always returns a
> u64, and phys_addr_t can be smaller than that.  So at least in this case
> the warning seems perfectly valid and the code has issues because it is
> mixing different concepts.

Sure, that seems like a reasonable way to look at things even if the
warning itself is a false positive.

> Where do you see warnings like this upstream?

I don't see this upstream, this is from patch 2 of this series:

https://lore.kernel.org/053fa4806a2c63efcde80caca473a8b670a2701c.1722249878.git.baruch@tkos.co.il/

Cheers,
Nathan


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2024-08-01 15:23 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-07-29 10:51 [PATCH v3 0/3] dma: support DMA zone starting above 4GB Baruch Siach
2024-07-29 10:51 ` [PATCH v3 1/3] dma-mapping: improve DMA zone selection Baruch Siach
2024-07-29 10:51 ` [PATCH v3 2/3] dma-mapping: replace zone_dma_bits by zone_dma_limit Baruch Siach
2024-07-29 20:20   ` kernel test robot
2024-07-30  2:12     ` Nathan Chancellor
2024-07-30 15:34       ` Christoph Hellwig
2024-08-01  1:24         ` Nathan Chancellor
2024-08-01 13:44           ` Christoph Hellwig
2024-08-01 15:22             ` Nathan Chancellor
2024-07-31 17:26   ` Catalin Marinas
2024-07-29 10:51 ` [PATCH v3 3/3] dma-direct: use RAM start to offset zone_dma_limit Baruch Siach
2024-07-31 17:33   ` Catalin Marinas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).