From: Frank Li <Frank.li@oss.nxp.com>
To: Koichiro Den <den@valinux.co.jp>
Cc: "Manivannan Sadhasivam" <mani@kernel.org>,
"Krzysztof Wilczyński" <kwilczynski@kernel.org>,
"Kishon Vijay Abraham I" <kishon@kernel.org>,
"Frank Li" <Frank.Li@kernel.org>,
"Niklas Cassel" <cassel@kernel.org>,
"Bjorn Helgaas" <bhelgaas@google.com>,
"Joao Pinto" <jpinto@synopsys.com>,
linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] PCI: endpoint: Fix BAR backing DMA address alignment
Date: Fri, 28 Aug 2026 16:40:00 -0500 [thread overview]
Message-ID: <apIAMJ98XJDsfjT6@SMW015318> (raw)
In-Reply-To: <20260827181757.1984374-1-den@valinux.co.jp>
On Fri, Aug 28, 2026 at 03:17:57AM +0900, Koichiro Den wrote:
> DWC BAR Match Mode requires the target address to be aligned to the BAR
> size. pci_epf_alloc_space() relies on dma_alloc_coherent() to provide
> that alignment. For CMA-backed allocations, the guaranteed physical
> alignment is capped at PAGE_SIZE << CONFIG_CMA_ALIGNMENT. With a direct
> DMA mapping, 4 KiB pages, and CONFIG_CMA_ALIGNMENT=8, a 2 MiB BAR may
> therefore receive a DMA address aligned to only 1 MiB.
> dw_pcie_prog_ep_inbound_atu() rejects such a mapping with -EINVAL.
>
> If the initial allocation is misaligned, free it and retry with
> mem_size - 1 bytes of padding. Select an aligned subrange and record its
> offset so pci_epf_free_space() can pass the original CPU address, DMA
> handle, and size to dma_free_coherent().
I understand this situation, but it mays waste memory, if 16MiB, it max
waste 16M-1 space.
As workaround, this is good enough.
add dt memory node for pcie-ep
my_dma_pool: dma@42000000 {
compatible = "shared-dma-pool";
reg = <0x42000000 0x02000000>;
reusable; /* <-- CMA: system CAN use these pages when idle */
};
pcie-ep {
...
memory-region = <&my_dma_pool>;
}
but if use "reusable", still meet CONFIG_CMA_ALIGNMENT. if use "no-map",
dma_alloc_from_dev_coherent() will bypass CONFIG_CMA_ALIGNMENT. but it will
waste memory if not use pcie-ep devices.
Maybe we try
static int __init rmem_cma_setup(unsigned long node, struct reserved_mem *rmem)
{
...
ret = cma_init_reserved_mem(rmem->base, rmem->size, 0, rmem->name, &cma);
if (ret) { ... }
+ /* linux,cma-force-align: bypass CONFIG_CMA_ALIGNMENT cap, align = get_order(size) */
+ if (of_get_flat_dt_prop(node, "linux,cma-force-align", NULL))
+ cma->force_align = true;
if (default_cma)
dma_contiguous_default_area = cma;
...
}
static struct page *cma_alloc_aligned(struct cma *cma, size_t size, gfp_t gfp)
{
- unsigned int align = min(get_order(size), CONFIG_CMA_ALIGNMENT);
+ unsigned int align;
+
+ if (cma && cma->force_align)
+ align = get_order(size); /* no cap: align = natural power-of-2 for size */
+ else
+ align = min(get_order(size), CONFIG_CMA_ALIGNMENT);
return cma_alloc(cma, size >> PAGE_SHIFT, align, gfp & __GFP_NOWARN);
}
I am not sure if DT team accept add "linux,cma-force-align", which desgin
for specic device CMA region only, not for default cmd. No impact to other
system.
Frank
>
> Fixes: 5e8cb4033807 ("PCI: endpoint: Add EP core layer to enable EP controller and EP functions")
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---
> drivers/pci/endpoint/pci-epf-core.c | 39 +++++++++++++++++++++++------
> include/linux/pci-epf.h | 7 ++++--
> 2 files changed, 37 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c
> index 6987343c9e61..e8c3709d85c4 100644
> --- a/drivers/pci/endpoint/pci-epf-core.c
> +++ b/drivers/pci/endpoint/pci-epf-core.c
> @@ -8,6 +8,7 @@
>
> #include <linux/device.h>
> #include <linux/dma-mapping.h>
> +#include <linux/overflow.h>
> #include <linux/slab.h>
> #include <linux/module.h>
>
> @@ -278,13 +279,15 @@ void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar,
> }
>
> dev = epc->dev.parent;
> - dma_free_coherent(dev, epf_bar[bar].mem_size, addr,
> - epf_bar[bar].phys_addr);
> + dma_free_coherent(dev, epf_bar[bar].mem_size,
> + (u8 *)addr - epf_bar[bar].alloc_offset,
> + epf_bar[bar].phys_addr - epf_bar[bar].alloc_offset);
>
> epf_bar[bar].phys_addr = 0;
> epf_bar[bar].addr = NULL;
> epf_bar[bar].size = 0;
> epf_bar[bar].mem_size = 0;
> + epf_bar[bar].alloc_offset = 0;
> epf_bar[bar].barno = 0;
> epf_bar[bar].flags = 0;
> }
> @@ -308,8 +311,10 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
> {
> struct pci_epf_bar *epf_bar;
> dma_addr_t phys_addr;
> + size_t alloc_offset = 0;
> struct pci_epc *epc;
> struct device *dev;
> + size_t alloc_size;
> size_t mem_size;
> void *space;
>
> @@ -326,16 +331,31 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
> }
>
> dev = epc->dev.parent;
> - space = dma_alloc_coherent(dev, mem_size, &phys_addr, GFP_KERNEL);
> - if (!space) {
> - dev_err(dev, "failed to allocate mem space\n");
> - return NULL;
> + alloc_size = mem_size;
> + space = dma_alloc_coherent(dev, alloc_size, &phys_addr, GFP_KERNEL);
> + if (!space)
> + goto err_alloc;
> + if (!IS_ALIGNED(phys_addr, mem_size)) {
> + dma_free_coherent(dev, alloc_size, space, phys_addr);
> +
> + if (check_add_overflow(mem_size, mem_size - 1, &alloc_size))
> + return NULL;
> +
> + space = dma_alloc_coherent(dev, alloc_size, &phys_addr,
> + GFP_KERNEL);
> + if (!space)
> + goto err_alloc;
> +
> + alloc_offset = ALIGN(phys_addr, mem_size) - phys_addr;
> + space = (u8 *)space + alloc_offset;
> + phys_addr += alloc_offset;
> }
>
> epf_bar[bar].phys_addr = phys_addr;
> epf_bar[bar].addr = space;
> epf_bar[bar].size = size;
> - epf_bar[bar].mem_size = mem_size;
> + epf_bar[bar].mem_size = alloc_size;
> + epf_bar[bar].alloc_offset = alloc_offset;
> epf_bar[bar].barno = bar;
> if (upper_32_bits(size) || epc_features->bar[bar].only_64bit)
> epf_bar[bar].flags |= PCI_BASE_ADDRESS_MEM_TYPE_64;
> @@ -343,6 +363,10 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
> epf_bar[bar].flags |= PCI_BASE_ADDRESS_MEM_TYPE_32;
>
> return space;
> +
> +err_alloc:
> + dev_err(dev, "failed to allocate mem space\n");
> + return NULL;
> }
> EXPORT_SYMBOL_GPL(pci_epf_alloc_space);
>
> @@ -413,6 +437,7 @@ int pci_epf_assign_bar_space(struct pci_epf *epf, size_t size,
> epf_bar[bar].addr = NULL;
> epf_bar[bar].size = bar_size;
> epf_bar[bar].mem_size = aligned_mem_size;
> + epf_bar[bar].alloc_offset = 0;
> epf_bar[bar].barno = bar;
> if (upper_32_bits(size) || epc_features->bar[bar].only_64bit)
> epf_bar[bar].flags |= PCI_BASE_ADDRESS_MEM_TYPE_64;
> diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
> index 8a6c64a35890..749c6611d7b9 100644
> --- a/include/linux/pci-epf.h
> +++ b/include/linux/pci-epf.h
> @@ -131,8 +131,10 @@ struct pci_epf_bar_submap {
> * @phys_addr: physical address that should be mapped to the BAR
> * @addr: virtual address corresponding to the @phys_addr
> * @size: the size of the address space present in BAR
> - * @mem_size: the size actually allocated to accommodate the iATU alignment
> - * requirement
> + * @mem_size: size of the coherent allocation, including alignment padding, or
> + * the required aligned backing size for assigned BAR space
> + * @alloc_offset: offset from the coherent allocation's CPU and DMA base
> + * addresses to @addr and @phys_addr
> * @barno: BAR number
> * @flags: flags that are set for the BAR
> * @num_submap: number of entries in @submap
> @@ -144,6 +146,7 @@ struct pci_epf_bar {
> void *addr;
> size_t size;
> size_t mem_size;
> + size_t alloc_offset;
> enum pci_barno barno;
> int flags;
>
>
> base-commit: 0a6f72eda328c773324555491e1ad7f0b0153155
> --
> 2.51.0
>
next prev parent reply other threads:[~2026-08-28 21:40 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-27 18:17 [PATCH] PCI: endpoint: Fix BAR backing DMA address alignment Koichiro Den
2026-08-27 18:25 ` sashiko-bot
2026-08-28 21:40 ` Frank Li [this message]
2026-08-29 16:22 ` Koichiro Den
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=apIAMJ98XJDsfjT6@SMW015318 \
--to=frank.li@oss.nxp.com \
--cc=Frank.Li@kernel.org \
--cc=bhelgaas@google.com \
--cc=cassel@kernel.org \
--cc=den@valinux.co.jp \
--cc=jpinto@synopsys.com \
--cc=kishon@kernel.org \
--cc=kwilczynski@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=mani@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.