From: Marek Szyprowski <m.szyprowski@samsung.com>
To: Jakub Kicinski <kuba@kernel.org>, robin.murphy@arm.com
Cc: netdev@vger.kernel.org, iommu@lists.linux.dev, joro@8bytes.org,
will@kernel.org, "Björn Töpel" <bjorn@kernel.org>
Subject: Re: [PATCH 01/11] dma-mapping: add dma_alloc_attrs_node() and dma_alloc_coherent_node()
Date: Sat, 7 Nov 2026 00:41:23 +0100 [thread overview]
Message-ID: <5b38b9ca-a3af-45db-82a4-4e2cc4600796@samsung.com> (raw)
In-Reply-To: <20261106184433.761422-2-kuba@kernel.org>
On 06.11.2026 19:44, Jakub Kicinski wrote:
> Coherent DMA memory is always allocated on the NUMA node of the device.
> That's the right choice for memory mostly accessed by the device, but
> some coherent allocations are accessed by the CPU on every operation.
> For example a NIC's descriptor and completion rings are written and
> read by the CPU servicing the queue, which may well be on a different
> node than the device. Placing such rings on the device's node means
> the CPU accesses remote memory in the fast path.
>
> Drivers work around this today by temporarily changing the node
> of the device with set_dev_node() around dma_alloc_coherent()
> (mlx4, mlx5, ixgbe, xgbe). This is racy against anything else
> looking at the device's node at the same time.
>
> Add dma_alloc_attrs_node() which takes the node explicitly, and
> a dma_alloc_coherent_node() wrapper. dma_alloc_attrs() now passes
> dev_to_node().
>
> The node is only a preference, the same as for kmalloc_node().
> Nothing takes it into account yet, following patches wire it up
> in dma-direct and iommu-dma. Allocations from fixed pools and from
> dma_map_ops->alloc implementations will keep ignoring it.
>
> Add an explicit new export instead of using static inline wrappers
> because we want the new API to be GPL-only.
>
> Reviewed-by: Björn Töpel <bjorn@kernel.org>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Acked-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
> v1:
> - move before the patches wiring up the node in dma-direct, iommu-dma
> and CMA (Robin)
> - dma-api.rst: drop the NUMA_NO_NODE suggestion (Björn)
> - docs: describe how the node is handled in the patches wiring it up,
> drop the mention of dma_free_coherent()
> - explain the separate GPL-only export in the commit message (Marek)
> rfc: https://lore.kernel.org/20261027022528.633359-5-kuba@kernel.org
> ---
> Documentation/core-api/dma-api.rst | 13 +++++++++++++
> include/linux/dma-mapping.h | 14 ++++++++++++++
> kernel/dma/mapping.c | 26 ++++++++++++++++++++++++--
> 3 files changed, 51 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/core-api/dma-api.rst b/Documentation/core-api/dma-api.rst
> index 69d4ebe4f96d..5d079507ffa1 100644
> --- a/Documentation/core-api/dma-api.rst
> +++ b/Documentation/core-api/dma-api.rst
> @@ -57,6 +57,19 @@ The flag parameter allows the caller to specify the ``GFP_`` flags (see
> kmalloc()) for the allocation (the implementation may ignore flags that affect
> the location of the returned memory, like GFP_DMA).
>
> +::
> +
> + void *
> + dma_alloc_coherent_node(struct device *dev, size_t size,
> + dma_addr_t *dma_handle, gfp_t flag, int node)
> +
> +Same as dma_alloc_coherent(), but places the memory on the given NUMA node
> +rather than on the node of the device. This is useful for memory accessed
> +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.
> +
> ::
>
> void
> diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
> index efde0e5a58dc..f8529f761823 100644
> --- a/include/linux/dma-mapping.h
> +++ b/include/linux/dma-mapping.h
> @@ -188,6 +188,8 @@ void dma_unmap_resource(struct device *dev, dma_addr_t addr, size_t size,
> enum dma_data_direction dir, unsigned long attrs);
> void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
> gfp_t flag, unsigned long attrs);
> +void *dma_alloc_attrs_node(struct device *dev, size_t size,
> + dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs, int node);
> void dma_free_attrs(struct device *dev, size_t size, void *cpu_addr,
> dma_addr_t dma_handle, unsigned long attrs);
> void *dmam_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
> @@ -273,6 +275,11 @@ static inline void *dma_alloc_attrs(struct device *dev, size_t size,
> {
> return NULL;
> }
> +static inline void *dma_alloc_attrs_node(struct device *dev, size_t size,
> + dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs, int node)
> +{
> + return NULL;
> +}
> static inline void dma_free_attrs(struct device *dev, size_t size,
> void *cpu_addr, dma_addr_t dma_handle, unsigned long attrs)
> {
> @@ -626,6 +633,13 @@ static inline void *dma_alloc_coherent(struct device *dev, size_t size,
> (gfp & __GFP_NOWARN) ? DMA_ATTR_NO_WARN : 0);
> }
>
> +static inline void *dma_alloc_coherent_node(struct device *dev, size_t size,
> + dma_addr_t *dma_handle, gfp_t gfp, int node)
> +{
> + return dma_alloc_attrs_node(dev, size, dma_handle, gfp,
> + (gfp & __GFP_NOWARN) ? DMA_ATTR_NO_WARN : 0, node);
> +}
> +
> static inline void dma_free_coherent(struct device *dev, size_t size,
> void *cpu_addr, dma_addr_t dma_handle)
> {
> diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c
> index 82e701648d60..1b1cd3bc4a40 100644
> --- a/kernel/dma/mapping.c
> +++ b/kernel/dma/mapping.c
> @@ -630,8 +630,22 @@ u64 dma_get_required_mask(struct device *dev)
> }
> EXPORT_SYMBOL_GPL(dma_get_required_mask);
>
> -void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
> - gfp_t flag, unsigned long attrs)
> +/**
> + * dma_alloc_attrs_node - allocate coherent memory on a given NUMA node
> + * @dev: device to allocate the memory for
> + * @size: size of the allocation
> + * @dma_handle: returns the DMA address of the allocation
> + * @flag: GFP flags for the allocation
> + * @attrs: DMA_ATTR_* flags for the allocation
> + * @node: NUMA node to allocate the memory on, NUMA_NO_NODE for no preference
> + *
> + * 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.
> + *
> + * Return: the CPU address of the allocation, or NULL on failure.
> + */
> +void *dma_alloc_attrs_node(struct device *dev, size_t size,
> + dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs, int node)
> {
> const struct dma_map_ops *ops = get_dma_ops(dev);
> void *cpu_addr;
> @@ -681,6 +695,14 @@ void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
> debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr, attrs);
> return cpu_addr;
> }
> +EXPORT_SYMBOL_GPL(dma_alloc_attrs_node);
> +
> +void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
> + gfp_t flag, unsigned long attrs)
> +{
> + return dma_alloc_attrs_node(dev, size, dma_handle, flag, attrs,
> + dev_to_node(dev));
> +}
> EXPORT_SYMBOL(dma_alloc_attrs);
>
> void dma_free_attrs(struct device *dev, size_t size, void *cpu_addr,
Best regards
--
Marek Szyprowski, PhD
Samsung R&D Institute Poland
next prev parent reply other threads:[~2026-11-06 23:41 UTC|newest]
Thread overview: 16+ 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 [this message]
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 ` [PATCH 04/11] dma-contiguous: pass the NUMA node to dma_alloc_contiguous() Jakub Kicinski
2026-11-12 9:53 ` Paolo Abeni
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-12 12:31 ` Tariq Toukan
2026-11-06 18:44 ` [PATCH 11/11] eth: mlx4: " Jakub Kicinski
2026-11-12 12:32 ` Tariq Toukan
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=5b38b9ca-a3af-45db-82a4-4e2cc4600796@samsung.com \
--to=m.szyprowski@samsung.com \
--cc=bjorn@kernel.org \
--cc=iommu@lists.linux.dev \
--cc=joro@8bytes.org \
--cc=kuba@kernel.org \
--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