[PATCH v4 1/3] PCI: endpoint: Add helper function pci_epf_get_bar_required_size()

Frank Li posted 3 patches 4 months, 1 week ago
There is a newer version of this series
[PATCH v4 1/3] PCI: endpoint: Add helper function pci_epf_get_bar_required_size()
Posted by Frank Li 4 months, 1 week ago
Introduce pci_epf_get_bar_required_size() to retrieve the required BAR
size and memory size. Prepare for adding support to set an MMIO address to
a specific BAR.

Use two variables 'aligned_bar_size' and 'aligned_mem_size' to avoid
confuse.

No functional changes.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v4
- use size_t *bar_size as in/out arugment.

change in v3
- change return value to int.
- use two pointers return bar size aligned and memory start address aligned
- update comments about why need memory align size. Actually iATU require
start address match aligned requirement. Since kernel return align to
size's address.
- use two varible aligned_bar_size and aligned_mem_size to avoid confuse
use 'size'.

change in v2
- new patch
---
 drivers/pci/endpoint/pci-epf-core.c | 81 +++++++++++++++++++++++--------------
 1 file changed, 51 insertions(+), 30 deletions(-)

diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c
index d54e18872aefc07c655c94c104a347328ff7a432..db0420f601d81de426a3e805c7fc309de58d54b7 100644
--- a/drivers/pci/endpoint/pci-epf-core.c
+++ b/drivers/pci/endpoint/pci-epf-core.c
@@ -208,6 +208,49 @@ void pci_epf_remove_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf)
 }
 EXPORT_SYMBOL_GPL(pci_epf_remove_vepf);
 
+static int
+pci_epf_get_bar_required_size(struct pci_epf *epf, size_t *bar_size,
+			      size_t *aligned_mem_size,
+			      enum pci_barno bar,
+			      const struct pci_epc_features *epc_features,
+			      enum pci_epc_interface_type type)
+{
+	u64 bar_fixed_size = epc_features->bar[bar].fixed_size;
+	size_t align = epc_features->align;
+	size_t size = *bar_size;
+
+	if (size < 128)
+		size = 128;
+
+	/* According to PCIe base spec, min size for a resizable BAR is 1 MB. */
+	if (epc_features->bar[bar].type == BAR_RESIZABLE && size < SZ_1M)
+		size = SZ_1M;
+
+	if (epc_features->bar[bar].type == BAR_FIXED && bar_fixed_size) {
+		if (size > bar_fixed_size) {
+			dev_err(&epf->dev,
+				"requested BAR size is larger than fixed size\n");
+			return -ENOMEM;
+		}
+		size = bar_fixed_size;
+	} else {
+		/* BAR size must be power of two */
+		size = roundup_pow_of_two(size);
+	}
+
+	*bar_size = size;
+
+	/*
+	 * The EPC's BAR start address must meet alignment requirements. In most
+	 * cases, the alignment will match the BAR size. However, differences
+	 * can occur—for example, when the fixed BAR size (e.g., 128 bytes) is
+	 * smaller than the required alignment (e.g., 4 KB).
+	 */
+	*aligned_mem_size = align ? ALIGN(size, align) : size;
+
+	return 0;
+}
+
 /**
  * pci_epf_free_space() - free the allocated PCI EPF register space
  * @epf: the EPF device from whom to free the memory
@@ -264,40 +307,16 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
 			  const struct pci_epc_features *epc_features,
 			  enum pci_epc_interface_type type)
 {
-	u64 bar_fixed_size = epc_features->bar[bar].fixed_size;
-	size_t aligned_size, align = epc_features->align;
 	struct pci_epf_bar *epf_bar;
+	size_t aligned_mem_size;
 	dma_addr_t phys_addr;
 	struct pci_epc *epc;
 	struct device *dev;
 	void *space;
 
-	if (size < 128)
-		size = 128;
-
-	/* According to PCIe base spec, min size for a resizable BAR is 1 MB. */
-	if (epc_features->bar[bar].type == BAR_RESIZABLE && size < SZ_1M)
-		size = SZ_1M;
-
-	if (epc_features->bar[bar].type == BAR_FIXED && bar_fixed_size) {
-		if (size > bar_fixed_size) {
-			dev_err(&epf->dev,
-				"requested BAR size is larger than fixed size\n");
-			return NULL;
-		}
-		size = bar_fixed_size;
-	} else {
-		/* BAR size must be power of two */
-		size = roundup_pow_of_two(size);
-	}
-
-	/*
-	 * Allocate enough memory to accommodate the iATU alignment
-	 * requirement.  In most cases, this will be the same as .size but
-	 * it might be different if, for example, the fixed size of a BAR
-	 * is smaller than align.
-	 */
-	aligned_size = align ? ALIGN(size, align) : size;
+	if (pci_epf_get_bar_required_size(epf, &size, &aligned_mem_size, bar,
+					  epc_features, type))
+		return NULL;
 
 	if (type == PRIMARY_INTERFACE) {
 		epc = epf->epc;
@@ -308,7 +327,9 @@ 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, aligned_size, &phys_addr, GFP_KERNEL);
+
+	space = dma_alloc_coherent(dev, aligned_mem_size,
+				   &phys_addr, GFP_KERNEL);
 	if (!space) {
 		dev_err(dev, "failed to allocate mem space\n");
 		return NULL;
@@ -317,7 +338,7 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
 	epf_bar[bar].phys_addr = phys_addr;
 	epf_bar[bar].addr = space;
 	epf_bar[bar].size = size;
-	epf_bar[bar].aligned_size = aligned_size;
+	epf_bar[bar].aligned_size = aligned_mem_size;
 	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;

-- 
2.34.1

Re: [PATCH v4 1/3] PCI: endpoint: Add helper function pci_epf_get_bar_required_size()
Posted by Niklas Cassel 4 months ago
On Tue, Sep 30, 2025 at 04:39:37PM -0400, Frank Li wrote:
> Introduce pci_epf_get_bar_required_size() to retrieve the required BAR
> size and memory size. Prepare for adding support to set an MMIO address to
> a specific BAR.
> 
> Use two variables 'aligned_bar_size' and 'aligned_mem_size' to avoid
> confuse.

'aligned_bar_size' has been renamed, so this sentence should be updated.


(snip)

> @@ -308,7 +327,9 @@ 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, aligned_size, &phys_addr, GFP_KERNEL);
> +
> +	space = dma_alloc_coherent(dev, aligned_mem_size,
> +				   &phys_addr, GFP_KERNEL);
>  	if (!space) {
>  		dev_err(dev, "failed to allocate mem space\n");
>  		return NULL;
> @@ -317,7 +338,7 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
>  	epf_bar[bar].phys_addr = phys_addr;
>  	epf_bar[bar].addr = space;
>  	epf_bar[bar].size = size;
> -	epf_bar[bar].aligned_size = aligned_size;
> +	epf_bar[bar].aligned_size = aligned_mem_size;

I like that this local variable is now named aligned_mem_size
to more clearly highlight that it is the aligned _memory_ size.

Perhaps you could also rename the struct pci_epf_bar struct member
'aligned_size' to 'aligned_mem_size' or perhaps even better,
'backing_mem_size' or 'mem_size' ?


Kind regards,
Niklas
Re: [PATCH v4 1/3] PCI: endpoint: Add helper function pci_epf_get_bar_required_size()
Posted by Frank Li 4 months ago
On Mon, Oct 06, 2025 at 12:43:52PM +0200, Niklas Cassel wrote:
> On Tue, Sep 30, 2025 at 04:39:37PM -0400, Frank Li wrote:
> > Introduce pci_epf_get_bar_required_size() to retrieve the required BAR
> > size and memory size. Prepare for adding support to set an MMIO address to
> > a specific BAR.
> >
> > Use two variables 'aligned_bar_size' and 'aligned_mem_size' to avoid
> > confuse.
>
> 'aligned_bar_size' has been renamed, so this sentence should be updated.
>
>
> (snip)
>
> > @@ -308,7 +327,9 @@ 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, aligned_size, &phys_addr, GFP_KERNEL);
> > +
> > +	space = dma_alloc_coherent(dev, aligned_mem_size,
> > +				   &phys_addr, GFP_KERNEL);
> >  	if (!space) {
> >  		dev_err(dev, "failed to allocate mem space\n");
> >  		return NULL;
> > @@ -317,7 +338,7 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
> >  	epf_bar[bar].phys_addr = phys_addr;
> >  	epf_bar[bar].addr = space;
> >  	epf_bar[bar].size = size;
> > -	epf_bar[bar].aligned_size = aligned_size;
> > +	epf_bar[bar].aligned_size = aligned_mem_size;
>
> I like that this local variable is now named aligned_mem_size
> to more clearly highlight that it is the aligned _memory_ size.
>
> Perhaps you could also rename the struct pci_epf_bar struct member
> 'aligned_size' to 'aligned_mem_size' or perhaps even better,
> 'backing_mem_size' or 'mem_size' ?

How about alloc_mem_size ? which actually used for dma_free() function.

Frank
>
>
> Kind regards,
> Niklas
Re: [PATCH v4 1/3] PCI: endpoint: Add helper function pci_epf_get_bar_required_size()
Posted by Niklas Cassel 4 months ago
On 7 October 2025 20:26:01 CEST, Frank Li <Frank.li@nxp.com> wrote:
>On Mon, Oct 06, 2025 at 12:43:52PM +0200, Niklas Cassel wrote:
>> On Tue, Sep 30, 2025 at 04:39:37PM -0400, Frank Li wrote:
>> > Introduce pci_epf_get_bar_required_size() to retrieve the required BAR
>> > size and memory size. Prepare for adding support to set an MMIO address to
>> > a specific BAR.
>> >
>> > Use two variables 'aligned_bar_size' and 'aligned_mem_size' to avoid
>> > confuse.
>>
>> 'aligned_bar_size' has been renamed, so this sentence should be updated.
>>
>>
>> (snip)
>>
>> > @@ -308,7 +327,9 @@ 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, aligned_size, &phys_addr, GFP_KERNEL);
>> > +
>> > +	space = dma_alloc_coherent(dev, aligned_mem_size,
>> > +				   &phys_addr, GFP_KERNEL);
>> >  	if (!space) {
>> >  		dev_err(dev, "failed to allocate mem space\n");
>> >  		return NULL;
>> > @@ -317,7 +338,7 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
>> >  	epf_bar[bar].phys_addr = phys_addr;
>> >  	epf_bar[bar].addr = space;
>> >  	epf_bar[bar].size = size;
>> > -	epf_bar[bar].aligned_size = aligned_size;
>> > +	epf_bar[bar].aligned_size = aligned_mem_size;
>>
>> I like that this local variable is now named aligned_mem_size
>> to more clearly highlight that it is the aligned _memory_ size.
>>
>> Perhaps you could also rename the struct pci_epf_bar struct member
>> 'aligned_size' to 'aligned_mem_size' or perhaps even better,
>> 'backing_mem_size' or 'mem_size' ?
>
>How about alloc_mem_size ? which actually used for dma_free() function.


I prefer mem_size, but I am not the maintainer.
Hopefully Mani has an option to avoid bike shedding :)

Have an awesome day!


/Niklas