Netdev List
 help / color / mirror / Atom feed
From: Jakub Kicinski <kuba@kernel.org>
To: robin.murphy@arm.com, m.szyprowski@samsung.com
Cc: netdev@vger.kernel.org, iommu@lists.linux.dev, joro@8bytes.org,
	will@kernel.org, "Jakub Kicinski" <kuba@kernel.org>,
	"Björn Töpel" <bjorn@kernel.org>
Subject: [PATCH 04/11] dma-contiguous: pass the NUMA node to dma_alloc_contiguous()
Date: Fri,  6 Nov 2026 10:44:26 -0800	[thread overview]
Message-ID: <20261106184433.761422-5-kuba@kernel.org> (raw)
In-Reply-To: <20261106184433.761422-1-kuba@kernel.org>

dma_alloc_contiguous() picks the per-numa CMA area based on the node of
the device. Let the callers pass the node in, so that dma-direct and
iommu-dma honor the node requested via dma_alloc_attrs_node() for CMA
allocations, too. dma_common_alloc_pages() keeps using the device's node.

Unlike the page allocator, CMA does not fall back to the areas of other
nodes, only to the global CMA area. The allocation may fail even though
the CMA area of the device's node still has free space. Document this.

This completes the wiring of the node, so also document which
allocations don't take it into account.

Acked-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Björn Töpel <bjorn@kernel.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
v1:
 - move after the dma-direct and iommu-dma patches (Robin)
 - docs: document that CMA does not fall back to other nodes' areas (Björn)
 - docs: document which allocations ignore the node
rfc: https://lore.kernel.org/20261027022528.633359-2-kuba@kernel.org
---
 Documentation/core-api/dma-api.rst |  5 ++++-
 include/linux/dma-map-ops.h        |  5 +++--
 drivers/iommu/dma-iommu.c          |  2 +-
 kernel/dma/contiguous.c            | 12 +++++-------
 kernel/dma/direct.c                |  2 +-
 kernel/dma/mapping.c               |  7 +++++++
 kernel/dma/ops_helpers.c           |  5 +++--
 7 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/Documentation/core-api/dma-api.rst b/Documentation/core-api/dma-api.rst
index f44cc770a472..e6fe24e936ee 100644
--- a/Documentation/core-api/dma-api.rst
+++ b/Documentation/core-api/dma-api.rst
@@ -69,7 +69,10 @@ frequently by both the device and a CPU on a different node, for example
 descriptor rings serviced by that CPU.
 
 Like with kmalloc_node() the node is only a preference, the page allocator
-may fall back to other nodes if the given node is out of memory.
+may fall back to other nodes if the given node is out of memory. Note that
+contiguous memory allocator (CMA) does not: only the CMA area of the given
+node and the global CMA area are tried. The allocation may fail even though
+the CMA area of another node, e.g. that of the device, still has free space.
 
 ::
 
diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h
index afaf2c12189b..6014ec433b03 100644
--- a/include/linux/dma-map-ops.h
+++ b/include/linux/dma-map-ops.h
@@ -102,7 +102,8 @@ struct page *dma_alloc_from_contiguous(struct device *dev, size_t count,
 				       unsigned int order, bool no_warn);
 bool dma_release_from_contiguous(struct device *dev, struct page *pages,
 				 int count);
-struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp);
+struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp,
+				  int nid);
 void dma_free_contiguous(struct device *dev, struct page *page, size_t size);
 
 void dma_contiguous_early_fixup(phys_addr_t base, unsigned long size);
@@ -136,7 +137,7 @@ static inline bool dma_release_from_contiguous(struct device *dev,
 }
 /* Use fallback alloc() and free() when CONFIG_DMA_CMA=n */
 static inline struct page *dma_alloc_contiguous(struct device *dev, size_t size,
-		gfp_t gfp)
+		gfp_t gfp, int nid)
 {
 	return NULL;
 }
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 3e3a1a987a23..b66e83cfbc5f 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -1648,7 +1648,7 @@ static void *iommu_dma_alloc_pages(struct device *dev, size_t size,
 	struct page *page = NULL;
 	void *cpu_addr;
 
-	page = dma_alloc_contiguous(dev, alloc_size, gfp);
+	page = dma_alloc_contiguous(dev, alloc_size, gfp, node);
 	if (!page) {
 		cpu_addr = alloc_pages_exact_nid(node, alloc_size, gfp);
 		if (!cpu_addr)
diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c
index 90937dc7c627..e30ec6a08af0 100644
--- a/kernel/dma/contiguous.c
+++ b/kernel/dma/contiguous.c
@@ -402,22 +402,20 @@ static struct page *cma_alloc_aligned(struct cma *cma, size_t size, gfp_t gfp)
  * @dev:   Pointer to device for which the allocation is performed.
  * @size:  Requested allocation size.
  * @gfp:   Allocation flags.
+ * @nid:   NUMA node to allocate the memory on.
  *
  * tries to use device specific contiguous memory area if available, or it
- * tries to use per-numa cma, if the allocation fails, it will fallback to
- * try default global one.
+ * tries to use per-numa cma of @nid, if the allocation fails, it will fallback
+ * to try default global one.
  *
  * Note that it bypass one-page size of allocations from the per-numa and
  * global area as the addresses within one page are always contiguous, so
  * there is no need to waste CMA pages for that kind; it also helps reduce
  * fragmentations.
  */
-struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)
+struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp,
+				  int nid)
 {
-#ifdef CONFIG_DMA_NUMA_CMA
-	int nid = dev_to_node(dev);
-#endif
-
 	/* CMA can be used only in the context which permits sleeping */
 	if (!gfpflags_allow_blocking(gfp))
 		return NULL;
diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index a9d24d8bc77c..37c49e84dea6 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -124,7 +124,7 @@ static struct page *__dma_direct_alloc_pages(struct device *dev, size_t size,
 	WARN_ON_ONCE(!PAGE_ALIGNED(size));
 
 	gfp |= dma_direct_optimal_gfp_mask(dev, &phys_limit);
-	page = dma_alloc_contiguous(dev, size, gfp);
+	page = dma_alloc_contiguous(dev, size, gfp, node);
 	if (page) {
 		if (dma_coherent_ok(dev, page_to_phys(page), size) &&
 		    (allow_highmem || !PageHighMem(page)))
diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c
index f98d4dec8649..b3d0811b1d82 100644
--- a/kernel/dma/mapping.c
+++ b/kernel/dma/mapping.c
@@ -642,6 +642,13 @@ EXPORT_SYMBOL_GPL(dma_get_required_mask);
  * Same as dma_alloc_attrs() but places the memory on @node rather than on the
  * node of @dev. Like with kmalloc_node() the node is only a preference,
  * the page allocator may fall back to other nodes if @node is out of memory.
+ * The contiguous memory allocator (CMA) does not: only the CMA area of @node
+ * and the global CMA area are tried. The allocation may fail even though the
+ * CMA area of another node, e.g. that of @dev, still has free space.
+ *
+ * Allocations served from per-device or global coherent pools, per-device CMA
+ * areas, restricted or atomic pools, arch_dma_alloc() or dma_map_ops
+ * implementations do not take @node into account.
  *
  * Return: the CPU address of the allocation, or NULL on failure.
  */
diff --git a/kernel/dma/ops_helpers.c b/kernel/dma/ops_helpers.c
index 5cdf3f60cf47..2bff02c53fb6 100644
--- a/kernel/dma/ops_helpers.c
+++ b/kernel/dma/ops_helpers.c
@@ -63,12 +63,13 @@ struct page *dma_common_alloc_pages(struct device *dev, size_t size,
 		dma_addr_t *dma_handle, enum dma_data_direction dir, gfp_t gfp)
 {
 	const struct dma_map_ops *ops = get_dma_ops(dev);
+	int nid = dev_to_node(dev);
 	struct page *page;
 	phys_addr_t phys;
 
-	page = dma_alloc_contiguous(dev, size, gfp);
+	page = dma_alloc_contiguous(dev, size, gfp, nid);
 	if (!page) {
-		void *va = alloc_pages_exact_nid(dev_to_node(dev), size, gfp);
+		void *va = alloc_pages_exact_nid(nid, size, gfp);
 
 		if (!va)
 			return NULL;
-- 
2.56.0


  parent reply	other threads:[~2026-11-06 18:44 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-06 18:44 [PATCH 00/11] dma-mapping: add dma_alloc_attrs_node() and dma_alloc_coherent_node() Jakub Kicinski
2026-11-06 18:44 ` [PATCH 01/11] " Jakub Kicinski
2026-11-06 23:41   ` Marek Szyprowski
2026-11-06 18:44 ` [PATCH 02/11] dma-direct: add dma_direct_alloc_node() Jakub Kicinski
2026-11-06 18:44 ` [PATCH 03/11] iommu/dma: pass the NUMA node to iommu_dma_alloc() Jakub Kicinski
2026-11-06 18:44 ` Jakub Kicinski [this message]
2026-11-06 18:44 ` [PATCH 05/11] eth: libwx: restore the device's NUMA node after ring allocation Jakub Kicinski
2026-11-06 18:44 ` [PATCH 06/11] eth: libwx: use dma_alloc_coherent_node() Jakub Kicinski
2026-11-06 18:44 ` [PATCH 07/11] eth: ixgbe: " Jakub Kicinski
2026-11-06 18:44 ` [PATCH 08/11] eth: xgbe: " Jakub Kicinski
2026-11-06 18:44 ` [PATCH 09/11] eth: fungible: " Jakub Kicinski
2026-11-06 18:44 ` [PATCH 10/11] eth: mlx5: " Jakub Kicinski
2026-11-06 18:44 ` [PATCH 11/11] eth: mlx4: " Jakub Kicinski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261106184433.761422-5-kuba@kernel.org \
    --to=kuba@kernel.org \
    --cc=bjorn@kernel.org \
    --cc=iommu@lists.linux.dev \
    --cc=joro@8bytes.org \
    --cc=m.szyprowski@samsung.com \
    --cc=netdev@vger.kernel.org \
    --cc=robin.murphy@arm.com \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox