mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/1] alpha: enable DMA CMA support (HAVE_DMA_CONTIGUOUS)
@ 2026-02-19 20:53 Magnus Lindholm
  2026-02-19 20:53 ` [PATCH 1/1] " Magnus Lindholm
  0 siblings, 1 reply; 3+ messages in thread
From: Magnus Lindholm @ 2026-02-19 20:53 UTC (permalink / raw)
  To: richard.henderson, mattst88, linux-kernel, linux-alpha, corbet,
	skhan, linux-doc
  Cc: glaubitz, macro, macro, mcree, ink, Magnus Lindholm

This series enables CONFIG_DMA_CMA support on Alpha by selecting
HAVE_DMA_CONTIGUOUS and wiring up the required architecture hooks.

Alpha previously relied solely on high-order page allocator
allocations for coherent DMA buffers. With memory compaction now
functional, CMA can be safely enabled to provide reliable
physically contiguous allocations under fragmentation.

Testing was performed on an Alpha UP2000+ (SMP) and a DS10 (UP)
using a custom kernel module that verified the following:

  - Correct CMA reservation via "cma=64M"
  - CmaTotal/CmaFree reporting in /proc/meminfo
  - Successful 32 MiB dma_alloc_coherent() allocations
  - CmaFree reduction and recovery after free
  - Successful allocations under heavy memory load

No allocation failures were observed.

Magnus Lindholm (1):
  alpha: enable DMA CMA support (HAVE_DMA_CONTIGUOUS)

 .../io/dma-contiguous/arch-support.txt        |  2 +-
 arch/alpha/Kconfig                            |  1 +
 arch/alpha/kernel/pci_iommu.c                 | 46 +++++++++++++++++++
 arch/alpha/kernel/setup.c                     | 16 +++++++
 4 files changed, 64 insertions(+), 1 deletion(-)

-- 
2.52.0


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

* [PATCH 1/1] alpha: enable DMA CMA support (HAVE_DMA_CONTIGUOUS)
  2026-02-19 20:53 [PATCH 0/1] alpha: enable DMA CMA support (HAVE_DMA_CONTIGUOUS) Magnus Lindholm
@ 2026-02-19 20:53 ` Magnus Lindholm
  2026-10-08 20:50   ` Matt Turner
  0 siblings, 1 reply; 3+ messages in thread
From: Magnus Lindholm @ 2026-02-19 20:53 UTC (permalink / raw)
  To: richard.henderson, mattst88, linux-kernel, linux-alpha, corbet,
	skhan, linux-doc
  Cc: glaubitz, macro, macro, mcree, ink, Magnus Lindholm

Alpha currently does not support CONFIG_DMA_CMA, even though the
generic CMA infrastructure is available. As a result, coherent DMA
allocations rely solely on the buddy allocator and may fail for large
contiguous buffers.

Add architecture support for HAVE_DMA_CONTIGUOUS by:

  - Selecting HAVE_DMA_CONTIGUOUS in arch/alpha/Kconfig.
  - Ensuring early command-line parameters are parsed in setup_arch()
    after Alpha-specific command line handling, so that the "cma="
    early parameter is honored.
  - Calling dma_contiguous_reserve() during early memory setup while
    memblock is active.
  - Extending alpha_pci_alloc_coherent() to fall back to
    dma_alloc_from_contiguous() when __get_free_pages() fails.
  - Extending alpha_pci_free_coherent() to release CMA-backed
    allocations via dma_release_from_contiguous().

With these changes, Alpha systems can successfully reserve and use
CMA-backed physically contiguous memory for DMA allocations.

Tested on a DS10 with cma=64M:
  - CMA reservation is correctly sized from the command line.

Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
 .../io/dma-contiguous/arch-support.txt        |  2 +-
 arch/alpha/Kconfig                            |  1 +
 arch/alpha/kernel/pci_iommu.c                 | 46 +++++++++++++++++++
 arch/alpha/kernel/setup.c                     | 16 +++++++
 4 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/Documentation/features/io/dma-contiguous/arch-support.txt b/Documentation/features/io/dma-contiguous/arch-support.txt
index 3c6ce35d704f..6cd205a991f6 100644
--- a/Documentation/features/io/dma-contiguous/arch-support.txt
+++ b/Documentation/features/io/dma-contiguous/arch-support.txt
@@ -6,7 +6,7 @@
     -----------------------
     |         arch |status|
     -----------------------
-    |       alpha: | TODO |
+    |       alpha: |  ok  |
     |         arc: | TODO |
     |         arm: |  ok  |
     |       arm64: |  ok  |
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 6c7dbf0adad6..e3ff6f7d93ab 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -2,6 +2,7 @@
 config ALPHA
 	bool
 	default y
+	select HAVE_DMA_CONTIGUOUS
 	select ARCH_32BIT_USTAT_F_TINODE
 	select ARCH_HAS_CURRENT_STACK_POINTER
 	select ARCH_HAS_DMA_OPS if PCI
diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c
index 955b6ca61627..08c18d49ca8e 100644
--- a/arch/alpha/kernel/pci_iommu.c
+++ b/arch/alpha/kernel/pci_iommu.c
@@ -15,6 +15,7 @@
 #include <linux/iommu-helper.h>
 #include <linux/string_choices.h>
 
+#include <linux/dma-map-ops.h>
 #include <asm/io.h>
 #include <asm/hwrpb.h>
 
@@ -409,12 +410,34 @@ static void *alpha_pci_alloc_coherent(struct device *dev, size_t size,
 	struct pci_dev *pdev = alpha_gendev_to_pci(dev);
 	void *cpu_addr;
 	long order = get_order(size);
+	unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+	struct page *cma_page = NULL;
 
+	/* Match existing behavior: prefer normal memory first. */
 	gfp &= ~GFP_DMA;
 
 try_again:
 	cpu_addr = (void *)__get_free_pages(gfp | __GFP_ZERO, order);
 	if (! cpu_addr) {
+		/*
+		 * Fallback to CMA if enabled: this can migrate/compact
+		 * movable pages out of the CMA area to form a contiguous bloc
+		 */
+		if (IS_ENABLED(CONFIG_DMA_CMA)) {
+			cma_page = dma_alloc_from_contiguous(dev, count, order, gfp);
+			if (cma_page) {
+				cpu_addr = page_address(cma_page);
+				if (!cpu_addr) {
+					/* Very unlikely on Alpha, but be safe. */
+					dma_release_from_contiguous(dev, cma_page, count);
+					cma_page = NULL;
+				} else {
+					memset(cpu_addr, 0, size);
+					goto have_mem;
+				}
+			}
+		}
+
 		printk(KERN_INFO "pci_alloc_consistent: "
 		       "get_free_pages failed from %ps\n",
 			__builtin_return_address(0));
@@ -422,11 +445,24 @@ static void *alpha_pci_alloc_coherent(struct device *dev, size_t size,
 		   with vmalloc and sg if we can't find contiguous memory.  */
 		return NULL;
 	}
+	/* __GFP_ZERO already did this, but keep the old behavior explicit. */
 	memset(cpu_addr, 0, size);
 
+have_mem:
 	*dma_addrp = pci_map_single_1(pdev, virt_to_phys(cpu_addr), size, 0);
 	if (*dma_addrp == DMA_MAPPING_ERROR) {
+		/*
+		 * Free the memory using the right backend:
+		 * - If it came from CMA, release to CMA
+		 * - Otherwise free_pages()
+		 */
+		if (IS_ENABLED(CONFIG_DMA_CMA)) {
+			if (dma_release_from_contiguous(dev, virt_to_page(cpu_addr), count))
+				goto map_failed_freed;
+		}
 		free_pages((unsigned long)cpu_addr, order);
+
+map_failed_freed:
 		if (alpha_mv.mv_pci_tbi || (gfp & GFP_DMA))
 			return NULL;
 		/* The address doesn't fit required mask and we
@@ -452,9 +488,19 @@ static void alpha_pci_free_coherent(struct device *dev, size_t size,
 				    unsigned long attrs)
 {
 	struct pci_dev *pdev = alpha_gendev_to_pci(dev);
+	unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+
 	dma_unmap_single(&pdev->dev, dma_addr, size, DMA_BIDIRECTIONAL);
+
+	if (IS_ENABLED(CONFIG_DMA_CMA)) {
+		/* Returns true if cpu_addr belongs to a CMA allocation. */
+		if (dma_release_from_contiguous(dev, virt_to_page(cpu_addr), count))
+			goto out;
+	}
+
 	free_pages((unsigned long)cpu_addr, get_order(size));
 
+out:
 	DBGA2("pci_free_consistent: [%llx,%zx] from %ps\n",
 	      dma_addr, size, __builtin_return_address(0));
 }
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index f0af444a69a4..24893bca39f5 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -46,6 +46,7 @@
 #include <asm/io.h>
 #include <linux/log2.h>
 #include <linux/export.h>
+#include <linux/dma-map-ops.h>
 
 static int alpha_panic_event(struct notifier_block *, unsigned long, void *);
 static struct notifier_block alpha_panic_block = {
@@ -513,6 +514,13 @@ setup_arch(char **cmdline_p)
 	/* Replace the command line, now that we've killed it with strsep.  */
 	strcpy(command_line, boot_command_line);
 
+	/*
+	 * Alpha mutates command_line with strsep() above, so make sure
+	 * early params (including "cma=") are parsed from the restored
+	 * command line before any CMA reservation happens.
+	 */
+	parse_early_param();
+
 	/* If we want SRM console printk echoing early, do it now. */
 	if (alpha_using_srm && srmcons_output) {
 		register_srm_console();
@@ -648,6 +656,14 @@ setup_arch(char **cmdline_p)
 		printk("Max ASN from HWRPB is bad (0x%lx)\n", hwrpb->max_asn);
  	}
 
+#ifdef CONFIG_CMA
+	/*
+	 * Reserve CMA now that memblock knows RAM layout and early params
+	 * (including cma=) have been parsed.
+	 */
+	dma_contiguous_reserve(0);
+#endif
+
 	/*
 	 * Identify the flock of penguins.
 	 */
-- 
2.52.0


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

* Re: [PATCH 1/1] alpha: enable DMA CMA support (HAVE_DMA_CONTIGUOUS)
  2026-02-19 20:53 ` [PATCH 1/1] " Magnus Lindholm
@ 2026-10-08 20:50   ` Matt Turner
  0 siblings, 0 replies; 3+ messages in thread
From: Matt Turner @ 2026-10-08 20:50 UTC (permalink / raw)
  To: Magnus Lindholm
  Cc: richard.henderson, linux-kernel, linux-alpha, corbet, skhan,
	linux-doc, glaubitz, macro, macro, mcree, ink

On Thu, Feb 19, 2026 at 9:53 PM Magnus Lindholm <linmag7@gmail.com> wrote:
> +           if (IS_ENABLED(CONFIG_DMA_CMA)) {
> +                   cma_page = dma_alloc_from_contiguous(dev, count, order, gfp);

Two problems here.

cma_alloc() can sleep, and alpha_pci_alloc_coherent() is called with
GFP_ATOMIC by some drivers. This needs a gfpflags_allow_blocking(gfp)
check before going to CMA.

The fourth argument of dma_alloc_from_contiguous() is "bool no_warn",
not a gfp mask, so passing gfp makes it always true.

Also, because the buddy allocator is tried first without __GFP_NOWARN,
a large allocation that then succeeds from CMA still produces a page
allocation failure splat.

I think all three go away, and the patch gets a lot smaller, if you
use the helpers dma-direct uses:

      page = dma_alloc_contiguous(dev, size, gfp);
      if (!page)
              page = alloc_pages(gfp | __GFP_ZERO, order);
      ...
      dma_free_contiguous(dev, virt_to_page(cpu_addr), size);

dma_alloc_contiguous() already refuses non-blocking callers, and
dma_free_contiguous() already falls back to __free_pages() when the
page is not in a CMA area. That removes the hand-rolled
release-or-free logic and both gotos.

> +                           cpu_addr = page_address(cma_page);
> +                           if (!cpu_addr) {

There is no highmem on alpha, so this cannot fail. Please drop it.

> +   /* __GFP_ZERO already did this, but keep the old behavior explicit. */

Either drop the redundant memset in a separate patch or leave the line
alone; the comment does not help.

> +   parse_early_param();

This moves the point at which every early_param() handler runs on
alpha, not only "cma=", from start_kernel() to the middle of
setup_arch(). I think that is fine, but it deserves its own patch and
changelog. The comment is also misleading: parse_early_param() works
on its own copy of boot_command_line, so the strsep() damage to
command_line is not the reason it is needed. It is needed because
dma_contiguous_reserve() now runs before start_kernel() gets to it.

> +#ifdef CONFIG_CMA
> +   dma_contiguous_reserve(0);
> +#endif

The #ifdef is not needed, there is a stub for !CONFIG_DMA_CMA.

About the limit of 0: setup_arch() has already switched memblock to
bottom-up at this point, so the area ends up low rather than at the
top of RAM. Where does it land on your machines? Two cases I would
like to understand:

 - Could a small area (say cma=4M) be placed below 16MB and eat into
   ZONE_DMA?
 - On machines without an IOMMU (mv_pci_tbi == NULL) the area has to
   sit inside the direct-map window to be usable at all. When
   pci_map_single_1() fails on a CMA page, the GFP_DMA retry will get
   the same CMA memory back.

Passing an explicit limit, and skipping CMA on the GFP_DMA retry,
would make both cases well defined.

The Kconfig hunk no longer applies to for-next, and the select should
go in sorted position.

Side note for the changelog: with CONFIG_DMA_CMA=y the default
CMA_SIZE_MBYTES is 16, so it is worth saying that 16MB is reserved
even without "cma=" on the command line.

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

end of thread, other threads:[~2026-10-08 20:50 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-02-19 20:53 [PATCH 0/1] alpha: enable DMA CMA support (HAVE_DMA_CONTIGUOUS) Magnus Lindholm
2026-02-19 20:53 ` [PATCH 1/1] " Magnus Lindholm
2026-10-08 20:50   ` Matt Turner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®