[PATCH v8 2/5] PCI: endpoint: Add BAR subrange mapping support

Koichiro Den posted 5 patches 3 weeks, 4 days ago
There is a newer version of this series
[PATCH v8 2/5] PCI: endpoint: Add BAR subrange mapping support
Posted by Koichiro Den 3 weeks, 4 days ago
Extend the PCI endpoint core to support mapping subranges within a BAR.
Add an optional 'submap' field in struct pci_epf_bar so an endpoint
function driver can request inbound mappings that fully cover the BAR.

Introduce a new EPC feature bit, subrange_mapping, and reject submap
requests from pci_epc_set_bar() unless the controller advertises both
subrange_mapping and dynamic_inbound_mapping features.

The submap array describes the complete BAR layout (no overlaps and no
gaps are allowed to avoid exposing untranslated address ranges). This
provides the generic infrastructure needed to map multiple logical
regions into a single BAR at different offsets, without assuming a
controller-specific inbound address translation mechanism.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 drivers/pci/endpoint/pci-epc-core.c |  8 ++++++++
 include/linux/pci-epc.h             |  4 ++++
 include/linux/pci-epf.h             | 27 +++++++++++++++++++++++++++
 3 files changed, 39 insertions(+)

diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index ca7f19cc973a..068155819c57 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -596,6 +596,14 @@ int pci_epc_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 	if (!epc_features)
 		return -EINVAL;
 
+	if (epf_bar->num_submap && !epf_bar->submap)
+		return -EINVAL;
+
+	if (epf_bar->num_submap &&
+	    !(epc_features->dynamic_inbound_mapping &&
+	      epc_features->subrange_mapping))
+		return -EINVAL;
+
 	if (epc_features->bar[bar].type == BAR_RESIZABLE &&
 	    (epf_bar->size < SZ_1M || (u64)epf_bar->size > (SZ_128G * 1024)))
 		return -EINVAL;
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 4c8516756c56..c021c7af175f 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -227,6 +227,9 @@ struct pci_epc_bar_desc {
  *                           inbound mappings for an already configured BAR
  *                           (i.e. allow calling pci_epc_set_bar() again
  *                           without first calling pci_epc_clear_bar())
+ * @subrange_mapping: indicate if the EPC device can map inbound subranges for a
+ *                    BAR. This feature depends on @dynamic_inbound_mapping
+ *                    feature.
  * @msi_capable: indicate if the endpoint function has MSI capability
  * @msix_capable: indicate if the endpoint function has MSI-X capability
  * @intx_capable: indicate if the endpoint can raise INTx interrupts
@@ -236,6 +239,7 @@ struct pci_epc_bar_desc {
 struct pci_epc_features {
 	unsigned int	linkup_notifier : 1;
 	unsigned int	dynamic_inbound_mapping : 1;
+	unsigned int	subrange_mapping : 1;
 	unsigned int	msi_capable : 1;
 	unsigned int	msix_capable : 1;
 	unsigned int	intx_capable : 1;
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index 48f68c4dcfa5..46f817da6e24 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -110,6 +110,26 @@ struct pci_epf_driver {
 
 #define to_pci_epf_driver(drv) container_of_const((drv), struct pci_epf_driver, driver)
 
+/**
+ * struct pci_epf_bar_submap - BAR subrange for inbound mapping
+ * @phys_addr: target physical/DMA address for this subrange
+ * @size: the size of the subrange to be mapped
+ *
+ * When pci_epf_bar.num_submap is >0, pci_epf_bar.submap describes the
+ * complete BAR layout. This allows an EPC driver to program multiple
+ * inbound translation windows for a single BAR when supported by the
+ * controller. The array order defines the BAR layout (submap[0] at offset
+ * 0, and each immediately follows the previous one).
+ *
+ * Note that the subranges:
+ * - must be non-overlapping
+ * - must exactly cover the BAR (i.e. no holes)
+ */
+struct pci_epf_bar_submap {
+	dma_addr_t	phys_addr;
+	size_t		size;
+};
+
 /**
  * struct pci_epf_bar - represents the BAR of EPF device
  * @phys_addr: physical address that should be mapped to the BAR
@@ -119,6 +139,9 @@ struct pci_epf_driver {
  *            requirement
  * @barno: BAR number
  * @flags: flags that are set for the BAR
+ * @num_submap: number of entries in @submap
+ * @submap: array of subrange descriptors allocated by the caller. See
+ *          struct pci_epf_bar_submap for the restrictions in detail.
  */
 struct pci_epf_bar {
 	dma_addr_t	phys_addr;
@@ -127,6 +150,10 @@ struct pci_epf_bar {
 	size_t		mem_size;
 	enum pci_barno	barno;
 	int		flags;
+
+	/* Optional sub-range mapping */
+	unsigned int	num_submap;
+	struct pci_epf_bar_submap	*submap;
 };
 
 /**
-- 
2.51.0
Re: [PATCH v8 2/5] PCI: endpoint: Add BAR subrange mapping support
Posted by Frank Li 3 weeks, 3 days ago
On Thu, Jan 15, 2026 at 05:49:25PM +0900, Koichiro Den wrote:
> Extend the PCI endpoint core to support mapping subranges within a BAR.
> Add an optional 'submap' field in struct pci_epf_bar so an endpoint
> function driver can request inbound mappings that fully cover the BAR.
>
> Introduce a new EPC feature bit, subrange_mapping, and reject submap
> requests from pci_epc_set_bar() unless the controller advertises both
> subrange_mapping and dynamic_inbound_mapping features.
>
> The submap array describes the complete BAR layout (no overlaps and no
> gaps are allowed to avoid exposing untranslated address ranges). This
> provides the generic infrastructure needed to map multiple logical
> regions into a single BAR at different offsets, without assuming a
> controller-specific inbound address translation mechanism.
>
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---
>  drivers/pci/endpoint/pci-epc-core.c |  8 ++++++++
>  include/linux/pci-epc.h             |  4 ++++
>  include/linux/pci-epf.h             | 27 +++++++++++++++++++++++++++
>  3 files changed, 39 insertions(+)
>
> diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
> index ca7f19cc973a..068155819c57 100644
> --- a/drivers/pci/endpoint/pci-epc-core.c
> +++ b/drivers/pci/endpoint/pci-epc-core.c
> @@ -596,6 +596,14 @@ int pci_epc_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
>  	if (!epc_features)
>  		return -EINVAL;
>
> +	if (epf_bar->num_submap && !epf_bar->submap)
> +		return -EINVAL;
> +
> +	if (epf_bar->num_submap &&
> +	    !(epc_features->dynamic_inbound_mapping &&
> +	      epc_features->subrange_mapping))
> +		return -EINVAL;
> +
>  	if (epc_features->bar[bar].type == BAR_RESIZABLE &&
>  	    (epf_bar->size < SZ_1M || (u64)epf_bar->size > (SZ_128G * 1024)))
>  		return -EINVAL;
> diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
> index 4c8516756c56..c021c7af175f 100644
> --- a/include/linux/pci-epc.h
> +++ b/include/linux/pci-epc.h
> @@ -227,6 +227,9 @@ struct pci_epc_bar_desc {
>   *                           inbound mappings for an already configured BAR
>   *                           (i.e. allow calling pci_epc_set_bar() again
>   *                           without first calling pci_epc_clear_bar())
> + * @subrange_mapping: indicate if the EPC device can map inbound subranges for a
> + *                    BAR. This feature depends on @dynamic_inbound_mapping
> + *                    feature.
>   * @msi_capable: indicate if the endpoint function has MSI capability
>   * @msix_capable: indicate if the endpoint function has MSI-X capability
>   * @intx_capable: indicate if the endpoint can raise INTx interrupts
> @@ -236,6 +239,7 @@ struct pci_epc_bar_desc {
>  struct pci_epc_features {
>  	unsigned int	linkup_notifier : 1;
>  	unsigned int	dynamic_inbound_mapping : 1;
> +	unsigned int	subrange_mapping : 1;
>  	unsigned int	msi_capable : 1;
>  	unsigned int	msix_capable : 1;
>  	unsigned int	intx_capable : 1;
> diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
> index 48f68c4dcfa5..46f817da6e24 100644
> --- a/include/linux/pci-epf.h
> +++ b/include/linux/pci-epf.h
> @@ -110,6 +110,26 @@ struct pci_epf_driver {
>
>  #define to_pci_epf_driver(drv) container_of_const((drv), struct pci_epf_driver, driver)
>
> +/**
> + * struct pci_epf_bar_submap - BAR subrange for inbound mapping
> + * @phys_addr: target physical/DMA address for this subrange
> + * @size: the size of the subrange to be mapped
> + *
> + * When pci_epf_bar.num_submap is >0, pci_epf_bar.submap describes the
> + * complete BAR layout. This allows an EPC driver to program multiple
> + * inbound translation windows for a single BAR when supported by the
> + * controller. The array order defines the BAR layout (submap[0] at offset
> + * 0, and each immediately follows the previous one).
> + *
> + * Note that the subranges:
> + * - must be non-overlapping
> + * - must exactly cover the BAR (i.e. no holes)

It is impossible after use 'size'. It can be removed.

> + */
> +struct pci_epf_bar_submap {
> +	dma_addr_t	phys_addr;
> +	size_t		size;
> +};
> +
>  /**
>   * struct pci_epf_bar - represents the BAR of EPF device
>   * @phys_addr: physical address that should be mapped to the BAR
> @@ -119,6 +139,9 @@ struct pci_epf_driver {
>   *            requirement
>   * @barno: BAR number
>   * @flags: flags that are set for the BAR
> + * @num_submap: number of entries in @submap
> + * @submap: array of subrange descriptors allocated by the caller. See
> + *          struct pci_epf_bar_submap for the restrictions in detail.
>   */
>  struct pci_epf_bar {
>  	dma_addr_t	phys_addr;
> @@ -127,6 +150,10 @@ struct pci_epf_bar {
>  	size_t		mem_size;
>  	enum pci_barno	barno;
>  	int		flags;
> +
> +	/* Optional sub-range mapping */
> +	unsigned int	num_submap;
> +	struct pci_epf_bar_submap	*submap;

struct pci_epf_bar_submap submap[] __counted_by(num_submap);

Not sure if use this simplify alloc/free.

Frank
>  };
>
>  /**
> --
> 2.51.0
>
Re: [PATCH v8 2/5] PCI: endpoint: Add BAR subrange mapping support
Posted by Koichiro Den 3 weeks ago
On Thu, Jan 15, 2026 at 09:52:58AM -0500, Frank Li wrote:
> On Thu, Jan 15, 2026 at 05:49:25PM +0900, Koichiro Den wrote:
> > Extend the PCI endpoint core to support mapping subranges within a BAR.
> > Add an optional 'submap' field in struct pci_epf_bar so an endpoint
> > function driver can request inbound mappings that fully cover the BAR.
> >
> > Introduce a new EPC feature bit, subrange_mapping, and reject submap
> > requests from pci_epc_set_bar() unless the controller advertises both
> > subrange_mapping and dynamic_inbound_mapping features.
> >
> > The submap array describes the complete BAR layout (no overlaps and no
> > gaps are allowed to avoid exposing untranslated address ranges). This
> > provides the generic infrastructure needed to map multiple logical
> > regions into a single BAR at different offsets, without assuming a
> > controller-specific inbound address translation mechanism.
> >
> > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > ---
> >  drivers/pci/endpoint/pci-epc-core.c |  8 ++++++++
> >  include/linux/pci-epc.h             |  4 ++++
> >  include/linux/pci-epf.h             | 27 +++++++++++++++++++++++++++
> >  3 files changed, 39 insertions(+)
> >
> > diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
> > index ca7f19cc973a..068155819c57 100644
> > --- a/drivers/pci/endpoint/pci-epc-core.c
> > +++ b/drivers/pci/endpoint/pci-epc-core.c
> > @@ -596,6 +596,14 @@ int pci_epc_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
> >  	if (!epc_features)
> >  		return -EINVAL;
> >
> > +	if (epf_bar->num_submap && !epf_bar->submap)
> > +		return -EINVAL;
> > +
> > +	if (epf_bar->num_submap &&
> > +	    !(epc_features->dynamic_inbound_mapping &&
> > +	      epc_features->subrange_mapping))
> > +		return -EINVAL;
> > +
> >  	if (epc_features->bar[bar].type == BAR_RESIZABLE &&
> >  	    (epf_bar->size < SZ_1M || (u64)epf_bar->size > (SZ_128G * 1024)))
> >  		return -EINVAL;
> > diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
> > index 4c8516756c56..c021c7af175f 100644
> > --- a/include/linux/pci-epc.h
> > +++ b/include/linux/pci-epc.h
> > @@ -227,6 +227,9 @@ struct pci_epc_bar_desc {
> >   *                           inbound mappings for an already configured BAR
> >   *                           (i.e. allow calling pci_epc_set_bar() again
> >   *                           without first calling pci_epc_clear_bar())
> > + * @subrange_mapping: indicate if the EPC device can map inbound subranges for a
> > + *                    BAR. This feature depends on @dynamic_inbound_mapping
> > + *                    feature.
> >   * @msi_capable: indicate if the endpoint function has MSI capability
> >   * @msix_capable: indicate if the endpoint function has MSI-X capability
> >   * @intx_capable: indicate if the endpoint can raise INTx interrupts
> > @@ -236,6 +239,7 @@ struct pci_epc_bar_desc {
> >  struct pci_epc_features {
> >  	unsigned int	linkup_notifier : 1;
> >  	unsigned int	dynamic_inbound_mapping : 1;
> > +	unsigned int	subrange_mapping : 1;
> >  	unsigned int	msi_capable : 1;
> >  	unsigned int	msix_capable : 1;
> >  	unsigned int	intx_capable : 1;
> > diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
> > index 48f68c4dcfa5..46f817da6e24 100644
> > --- a/include/linux/pci-epf.h
> > +++ b/include/linux/pci-epf.h
> > @@ -110,6 +110,26 @@ struct pci_epf_driver {
> >
> >  #define to_pci_epf_driver(drv) container_of_const((drv), struct pci_epf_driver, driver)
> >
> > +/**
> > + * struct pci_epf_bar_submap - BAR subrange for inbound mapping
> > + * @phys_addr: target physical/DMA address for this subrange
> > + * @size: the size of the subrange to be mapped
> > + *
> > + * When pci_epf_bar.num_submap is >0, pci_epf_bar.submap describes the
> > + * complete BAR layout. This allows an EPC driver to program multiple
> > + * inbound translation windows for a single BAR when supported by the
> > + * controller. The array order defines the BAR layout (submap[0] at offset
> > + * 0, and each immediately follows the previous one).
> > + *
> > + * Note that the subranges:
> > + * - must be non-overlapping
> > + * - must exactly cover the BAR (i.e. no holes)
> 
> It is impossible after use 'size'. It can be removed.

Agreed, those notes (ie non-overlapping/no holes) are redundant now.
Thanks for pointing it out. I'll drop them.

Koichiro

> 
> > + */
> > +struct pci_epf_bar_submap {
> > +	dma_addr_t	phys_addr;
> > +	size_t		size;
> > +};
> > +
> >  /**
> >   * struct pci_epf_bar - represents the BAR of EPF device
> >   * @phys_addr: physical address that should be mapped to the BAR
> > @@ -119,6 +139,9 @@ struct pci_epf_driver {
> >   *            requirement
> >   * @barno: BAR number
> >   * @flags: flags that are set for the BAR
> > + * @num_submap: number of entries in @submap
> > + * @submap: array of subrange descriptors allocated by the caller. See
> > + *          struct pci_epf_bar_submap for the restrictions in detail.
> >   */
> >  struct pci_epf_bar {
> >  	dma_addr_t	phys_addr;
> > @@ -127,6 +150,10 @@ struct pci_epf_bar {
> >  	size_t		mem_size;
> >  	enum pci_barno	barno;
> >  	int		flags;
> > +
> > +	/* Optional sub-range mapping */
> > +	unsigned int	num_submap;
> > +	struct pci_epf_bar_submap	*submap;
> 
> struct pci_epf_bar_submap submap[] __counted_by(num_submap);
> 
> Not sure if use this simplify alloc/free.
> 
> Frank
> >  };
> >
> >  /**
> > --
> > 2.51.0
> >
Re: [PATCH v8 2/5] PCI: endpoint: Add BAR subrange mapping support
Posted by Niklas Cassel 3 weeks, 3 days ago
On Thu, Jan 15, 2026 at 09:52:58AM -0500, Frank Li wrote:
> > @@ -127,6 +150,10 @@ struct pci_epf_bar {
> >  	size_t		mem_size;
> >  	enum pci_barno	barno;
> >  	int		flags;
> > +
> > +	/* Optional sub-range mapping */
> > +	unsigned int	num_submap;
> > +	struct pci_epf_bar_submap	*submap;
> 
> struct pci_epf_bar_submap submap[] __counted_by(num_submap);
> 
> Not sure if use this simplify alloc/free.

Your suggestion changes the submap from a pointer to a flexible array
member.

A flexible array member must always be last in the struct,
and you can only have one flexible array member per struct.

Additionally, using a flexible array member requires the struct to
always be allocated on the heap. You can't allocate a struct with a
flexible array member on the stack.

So I'm not sure that if your suggestion is something we want.


Kind regards,
Niklas
Re: [PATCH v8 2/5] PCI: endpoint: Add BAR subrange mapping support
Posted by Frank Li 3 weeks, 3 days ago
On Thu, Jan 15, 2026 at 04:21:21PM +0100, Niklas Cassel wrote:
> On Thu, Jan 15, 2026 at 09:52:58AM -0500, Frank Li wrote:
> > > @@ -127,6 +150,10 @@ struct pci_epf_bar {
> > >  	size_t		mem_size;
> > >  	enum pci_barno	barno;
> > >  	int		flags;
> > > +
> > > +	/* Optional sub-range mapping */
> > > +	unsigned int	num_submap;
> > > +	struct pci_epf_bar_submap	*submap;
> >
> > struct pci_epf_bar_submap submap[] __counted_by(num_submap);
> >
> > Not sure if use this simplify alloc/free.
>
> Your suggestion changes the submap from a pointer to a flexible array
> member.
>
> A flexible array member must always be last in the struct,
> and you can only have one flexible array member per struct.
>
> Additionally, using a flexible array member requires the struct to
> always be allocated on the heap. You can't allocate a struct with a
> flexible array member on the stack.
>
> So I'm not sure that if your suggestion is something we want.

Yes, forget my comments if not fit.

Frank
>
>
> Kind regards,
> Niklas