* [RFC PATCH] PCI: Get the hotplug bridge window sizes from DT
@ 2026-07-06 12:31 Manivannan Sadhasivam
2026-07-06 12:37 ` sashiko-bot
2026-07-06 17:06 ` Ilpo Järvinen
0 siblings, 2 replies; 3+ messages in thread
From: Manivannan Sadhasivam @ 2026-07-06 12:31 UTC (permalink / raw)
To: bhelgaas, robh, krzk+dt
Cc: linux-pci, linux-kernel, qiang.yu, Manivannan Sadhasivam
Most of the PCI hotplug bridges used in Devicetree platforms do not have
their bridge windows populated by firmware. So the PCI core allocates the
bridge windows based on the requirements below:
1. Total size needed by the downstream devices
2. Default size (2MiB for MMIO, 256 bytes for IO) if no devices are
available during the initial bus scan
3. Command line params like hpmemsize etc...
If no devices are available during the initial bus scan, then the PCI core
allocates the default conservative 2MiB MMIO bridge windows. But this size
sometimes becomes insufficient when a BAR hungry device like a GPU gets
plugged in later. So users have to resort to command line params to
increase the window sizes. But this is very inconvenient and causes a lot
of pain in distro integration.
To address this issue, parse the 'ranges' property from the bridge DT node
(if available) and use the sizes for each bridge window. This works well
because the 'ranges' property is already allowed by the DT binding for PCI
bridges and it lets system designers pre-define the hotplug bridge window
size requirements in firmware.
The DT derived sizes are applied as the additional (hotplug) reservation for
each window. Command line parameters (hpmemsize etc...) continue to take
precedence over DT.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
Sending this patch as RFC because I'm not 100% sure if 'ranges' if the correct
property here. I chose this property as it is already allowed for PCI bridges
and allows specifying the window sizes. But for this usecase, bridge start
addresses specified with this property are ignored.
Other option would be to introduce a new property to specify the bridge window
size.
But nevertheless, having a DT property for specifying the window sizes will help
with usecases like USB4 PCIe Tunnelling, multi-Root Port setups where firmware
doesn't pre-allocate the bridge windows.
drivers/pci/pci.c | 3 --
drivers/pci/pci.h | 4 +++
drivers/pci/setup-bus.c | 75 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 79 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index d34266651ad0..5b6474a18b51 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -102,9 +102,6 @@ bool pci_reset_supported(struct pci_dev *dev)
int pci_domains_supported = 1;
#endif
-#define DEFAULT_HOTPLUG_IO_SIZE (256)
-#define DEFAULT_HOTPLUG_MMIO_SIZE (2*1024*1024)
-#define DEFAULT_HOTPLUG_MMIO_PREF_SIZE (2*1024*1024)
/* hpiosize=nn can override this */
unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE;
/*
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 4a14f88e543a..055c9b8c052b 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -414,6 +414,10 @@ extern unsigned long pci_hotplug_mmio_size;
extern unsigned long pci_hotplug_mmio_pref_size;
extern unsigned long pci_hotplug_bus_size;
+#define DEFAULT_HOTPLUG_IO_SIZE (256)
+#define DEFAULT_HOTPLUG_MMIO_SIZE (2*1024*1024)
+#define DEFAULT_HOTPLUG_MMIO_PREF_SIZE (2*1024*1024)
+
static inline bool pci_is_cardbus_bridge(struct pci_dev *dev)
{
return dev->hdr_type == PCI_HEADER_TYPE_CARDBUS;
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 4cf120ebe5ad..3dc82e3d3fd5 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -29,6 +29,8 @@
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/acpi.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
#include "pci.h"
#define PCI_RES_TYPE_MASK \
@@ -1385,6 +1387,54 @@ static void pbus_size_mem(struct pci_bus *bus, struct resource *b_res,
}
}
+/*
+ * pci_bridge_of_get_window - Get bridge window from DT.
+ *
+ * If the bridge's DT node has a "ranges" property, then parse the property and
+ * return the bridge window sizes. This allows per-bridge resource allocation
+ * from DT.
+ *
+ * Return: 'true' if a valid 'ranges' property was found in DT node, with bridge
+ * window resources populated in @io, @mmio, @mmio_pref arguments. 'false'
+ * otherwise.
+ */
+static bool pci_bridge_of_get_window(struct pci_dev *dev,
+ struct resource *io,
+ struct resource *mmio,
+ struct resource *mmio_pref)
+{
+ struct device_node *np = dev->dev.of_node;
+ struct of_pci_range_parser parser;
+ struct of_pci_range range;
+ bool found = false;
+
+ if (!np || !of_property_present(np, "ranges"))
+ return false;
+
+ if (of_pci_range_parser_init(&parser, np))
+ return false;
+
+ for_each_of_pci_range(&parser, &range) {
+ struct resource *res;
+
+ if (range.flags & IORESOURCE_IO)
+ res = io;
+ else if (range.flags & IORESOURCE_PREFETCH)
+ res = mmio_pref;
+ else if (range.flags & IORESOURCE_MEM)
+ res = mmio;
+ else
+ continue;
+
+ res->flags = range.flags;
+ res->start = range.cpu_addr;
+ res->end = range.cpu_addr + range.size - 1;
+ found = true;
+ }
+
+ return found;
+}
+
void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
{
struct pci_dev *dev;
@@ -1430,9 +1480,34 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
case PCI_HEADER_TYPE_BRIDGE:
pci_bridge_check_ranges(bus);
if (bus->self->is_hotplug_bridge) {
+ struct resource dt_io = {}, dt_mmio = {}, dt_mmio_pref = {};
+
additional_io_size = pci_hotplug_io_size;
additional_mmio_size = pci_hotplug_mmio_size;
additional_mmio_pref_size = pci_hotplug_mmio_pref_size;
+
+ /*
+ * If the bridge has a DT ranges property, use that to
+ * override the default window sizes. Command line
+ * parameters (hpmemsize etc...) take precedence over
+ * DT.
+ */
+ if (pci_bridge_of_get_window(bus->self,
+ &dt_io, &dt_mmio,
+ &dt_mmio_pref)) {
+ if (dt_io.flags &&
+ pci_hotplug_io_size == DEFAULT_HOTPLUG_IO_SIZE)
+ additional_io_size =
+ resource_size(&dt_io);
+ if (dt_mmio.flags &&
+ pci_hotplug_mmio_size == DEFAULT_HOTPLUG_MMIO_SIZE)
+ additional_mmio_size =
+ resource_size(&dt_mmio);
+ if (dt_mmio_pref.flags &&
+ pci_hotplug_mmio_pref_size == DEFAULT_HOTPLUG_MMIO_PREF_SIZE)
+ additional_mmio_pref_size =
+ resource_size(&dt_mmio_pref);
+ }
}
fallthrough;
default:
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [RFC PATCH] PCI: Get the hotplug bridge window sizes from DT
2026-07-06 12:31 [RFC PATCH] PCI: Get the hotplug bridge window sizes from DT Manivannan Sadhasivam
@ 2026-07-06 12:37 ` sashiko-bot
2026-07-06 17:06 ` Ilpo Järvinen
1 sibling, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-07-06 12:37 UTC (permalink / raw)
To: Manivannan Sadhasivam; +Cc: linux-pci
> Most of the PCI hotplug bridges used in Devicetree platforms do not have
> their bridge windows populated by firmware. So the PCI core allocates the
> bridge windows based on the requirements below:
>
> 1. Total size needed by the downstream devices
> 2. Default size (2MiB for MMIO, 256 bytes for IO) if no devices are
> available during the initial bus scan
> 3. Command line params like hpmemsize etc...
>
> If no devices are available during the initial bus scan, then the PCI core
> allocates the default conservative 2MiB MMIO bridge windows. But this size
> sometimes becomes insufficient when a BAR hungry device like a GPU gets
> plugged in later. So users have to resort to command line params to
> increase the window sizes. But this is very inconvenient and causes a lot
> of pain in distro integration.
>
> To address this issue, parse the 'ranges' property from the bridge DT node
> (if available) and use the sizes for each bridge window. This works well
> because the 'ranges' property is already allowed by the DT binding for PCI
> bridges and it lets system designers pre-define the hotplug bridge window
> size requirements in firmware.
>
> The DT derived sizes are applied as the additional (hotplug) reservation for
> each window. Command line parameters (hpmemsize etc...) continue to take
> precedence over DT.
>
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260706123133.545104-1-manivannan.sadhasivam@oss.qualcomm.com?part=1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [RFC PATCH] PCI: Get the hotplug bridge window sizes from DT
2026-07-06 12:31 [RFC PATCH] PCI: Get the hotplug bridge window sizes from DT Manivannan Sadhasivam
2026-07-06 12:37 ` sashiko-bot
@ 2026-07-06 17:06 ` Ilpo Järvinen
1 sibling, 0 replies; 3+ messages in thread
From: Ilpo Järvinen @ 2026-07-06 17:06 UTC (permalink / raw)
To: Manivannan Sadhasivam; +Cc: bhelgaas, robh, krzk+dt, linux-pci, LKML, qiang.yu
On Mon, 6 Jul 2026, Manivannan Sadhasivam wrote:
> Most of the PCI hotplug bridges used in Devicetree platforms do not have
> their bridge windows populated by firmware. So the PCI core allocates the
> bridge windows based on the requirements below:
>
> 1. Total size needed by the downstream devices
> 2. Default size (2MiB for MMIO, 256 bytes for IO) if no devices are
> available during the initial bus scan
> 3. Command line params like hpmemsize etc...
>
> If no devices are available during the initial bus scan, then the PCI core
> allocates the default conservative 2MiB MMIO bridge windows. But this size
> sometimes becomes insufficient when a BAR hungry device like a GPU gets
> plugged in later. So users have to resort to command line params to
> increase the window sizes. But this is very inconvenient and causes a lot
> of pain in distro integration.
>
> To address this issue, parse the 'ranges' property from the bridge DT node
> (if available) and use the sizes for each bridge window. This works well
> because the 'ranges' property is already allowed by the DT binding for PCI
> bridges and it lets system designers pre-define the hotplug bridge window
> size requirements in firmware.
>
> The DT derived sizes are applied as the additional (hotplug) reservation for
> each window. Command line parameters (hpmemsize etc...) continue to take
> precedence over DT.
>
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
> ---
>
> Sending this patch as RFC because I'm not 100% sure if 'ranges' if the correct
> property here. I chose this property as it is already allowed for PCI bridges
> and allows specifying the window sizes. But for this usecase, bridge start
> addresses specified with this property are ignored.
>
> Other option would be to introduce a new property to specify the bridge window
> size.
>
> But nevertheless, having a DT property for specifying the window sizes will help
> with usecases like USB4 PCIe Tunnelling, multi-Root Port setups where firmware
> doesn't pre-allocate the bridge windows.
>
> drivers/pci/pci.c | 3 --
> drivers/pci/pci.h | 4 +++
> drivers/pci/setup-bus.c | 75 +++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 79 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index d34266651ad0..5b6474a18b51 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -102,9 +102,6 @@ bool pci_reset_supported(struct pci_dev *dev)
> int pci_domains_supported = 1;
> #endif
>
> -#define DEFAULT_HOTPLUG_IO_SIZE (256)
> -#define DEFAULT_HOTPLUG_MMIO_SIZE (2*1024*1024)
> -#define DEFAULT_HOTPLUG_MMIO_PREF_SIZE (2*1024*1024)
> /* hpiosize=nn can override this */
> unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE;
> /*
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 4a14f88e543a..055c9b8c052b 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -414,6 +414,10 @@ extern unsigned long pci_hotplug_mmio_size;
> extern unsigned long pci_hotplug_mmio_pref_size;
> extern unsigned long pci_hotplug_bus_size;
>
> +#define DEFAULT_HOTPLUG_IO_SIZE (256)
> +#define DEFAULT_HOTPLUG_MMIO_SIZE (2*1024*1024)
> +#define DEFAULT_HOTPLUG_MMIO_PREF_SIZE (2*1024*1024)
It would be nice to convert these to SZ_* as we're touching them now.
Consider moving defines + variables into setup-bus.c as they're more
relevant there.
> +
> static inline bool pci_is_cardbus_bridge(struct pci_dev *dev)
> {
> return dev->hdr_type == PCI_HEADER_TYPE_CARDBUS;
> diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
> index 4cf120ebe5ad..3dc82e3d3fd5 100644
> --- a/drivers/pci/setup-bus.c
> +++ b/drivers/pci/setup-bus.c
> @@ -29,6 +29,8 @@
> #include <linux/sizes.h>
> #include <linux/slab.h>
> #include <linux/acpi.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> #include "pci.h"
>
> #define PCI_RES_TYPE_MASK \
> @@ -1385,6 +1387,54 @@ static void pbus_size_mem(struct pci_bus *bus, struct resource *b_res,
> }
> }
>
> +/*
> + * pci_bridge_of_get_window - Get bridge window from DT.
> + *
> + * If the bridge's DT node has a "ranges" property, then parse the property and
> + * return the bridge window sizes. This allows per-bridge resource allocation
> + * from DT.
> + *
> + * Return: 'true' if a valid 'ranges' property was found in DT node, with bridge
> + * window resources populated in @io, @mmio, @mmio_pref arguments. 'false'
> + * otherwise.
> + */
> +static bool pci_bridge_of_get_window(struct pci_dev *dev,
> + struct resource *io,
> + struct resource *mmio,
> + struct resource *mmio_pref)
> +{
> + struct device_node *np = dev->dev.of_node;
> + struct of_pci_range_parser parser;
> + struct of_pci_range range;
> + bool found = false;
> +
> + if (!np || !of_property_present(np, "ranges"))
> + return false;
> +
> + if (of_pci_range_parser_init(&parser, np))
> + return false;
> +
> + for_each_of_pci_range(&parser, &range) {
> + struct resource *res;
> +
> + if (range.flags & IORESOURCE_IO)
> + res = io;
> + else if (range.flags & IORESOURCE_PREFETCH)
> + res = mmio_pref;
> + else if (range.flags & IORESOURCE_MEM)
> + res = mmio;
I wonder what should this do with the recent PCIe spec change that allows
64-bit non-prefetchable resources. Does/will DT keep using the prefetch
flagas the differentiator for 32-bit vs 64-bit window?
There was discussion some months (or perhaps a year by now) back about
this on general level and it seemed Bjorn was leaning towards PCI core
allowing 64-bit non-pref resources into the "prefetchable" window in
cases where things are pure PCIe.
I readily admit I'm pretty unfamiliar when it comes to DT (and have had to
look at them only while looking into some PCI resource regressions) so
please take that into account while considering this feedback, I may miss
some critical understanding about DT,
> + else
> + continue;
> +
> + res->flags = range.flags;
> + res->start = range.cpu_addr;
> + res->end = range.cpu_addr + range.size - 1;
resource_set_range()
> + found = true;
> + }
> +
> + return found;
> +}
> +
> void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
> {
> struct pci_dev *dev;
> @@ -1430,9 +1480,34 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
> case PCI_HEADER_TYPE_BRIDGE:
> pci_bridge_check_ranges(bus);
> if (bus->self->is_hotplug_bridge) {
> + struct resource dt_io = {}, dt_mmio = {}, dt_mmio_pref = {};
> +
> additional_io_size = pci_hotplug_io_size;
> additional_mmio_size = pci_hotplug_mmio_size;
> additional_mmio_pref_size = pci_hotplug_mmio_pref_size;
> +
> + /*
> + * If the bridge has a DT ranges property, use that to
> + * override the default window sizes. Command line
> + * parameters (hpmemsize etc...) take precedence over
> + * DT.
> + */
> + if (pci_bridge_of_get_window(bus->self,
> + &dt_io, &dt_mmio,
> + &dt_mmio_pref)) {
Fits to 2 lines.
> + if (dt_io.flags &&
> + pci_hotplug_io_size == DEFAULT_HOTPLUG_IO_SIZE)
> + additional_io_size =
> + resource_size(&dt_io);
> + if (dt_mmio.flags &&
> + pci_hotplug_mmio_size == DEFAULT_HOTPLUG_MMIO_SIZE)
> + additional_mmio_size =
> + resource_size(&dt_mmio);
> + if (dt_mmio_pref.flags &&
> + pci_hotplug_mmio_pref_size == DEFAULT_HOTPLUG_MMIO_PREF_SIZE)
> + additional_mmio_pref_size =
> + resource_size(&dt_mmio_pref);
As noted also by sashiko, giving a cmdline argument with the default value
would be overriden.
> + }
> }
> fallthrough;
> default:
>
--
i.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-06 17:06 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-06 12:31 [RFC PATCH] PCI: Get the hotplug bridge window sizes from DT Manivannan Sadhasivam
2026-07-06 12:37 ` sashiko-bot
2026-07-06 17:06 ` Ilpo Järvinen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox