* [PATCH 01/23] PCI: Fix bridge window alignment with optional resources
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 02/23] PCI: Rewrite bridge window head alignment function Ilpo Järvinen
` (22 subsequent siblings)
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski,
Benjamin Herrenschmidt, Wei Yang, linux-kernel
Cc: Ilpo Järvinen, Malte Schröder, stable
pbus_size_mem() has two alignments, one for required resources in
min_align and another in add_align that takes account optional
resources.
The add_align is applied to the bridge window through the realloc_head
list. It can happen, however, that add_align is larger than min_align
but calculated size1 and size0 are equal due to extra tailroom (e.g.,
hotplug reservation, tail alignment), and therefore no entry is created
to the realloc_head list. Without the bridge appearing in the realloc
head, add_align is lost when pbus_size_mem() returns.
The problem is visible in this log for 0000:05:00.0 which lacks
add_size ... add_align ... line that would indicate it was added into
the realloc_head list:
pci 0000:05:00.0: PCI bridge to [bus 06-16]
...
pci 0000:06:00.0: bridge window [mem 0x00100000-0x001fffff] to [bus 07] requires relaxed alignment rules
pci 0000:06:06.0: bridge window [mem 0x00100000-0x001fffff] to [bus 0a] requires relaxed alignment rules
pci 0000:06:07.0: bridge window [mem 0x00100000-0x003fffff] to [bus 0b] requires relaxed alignment rules
pci 0000:06:08.0: bridge window [mem 0x00800000-0x00ffffff 64bit pref] to [bus 0c-14] requires relaxed alignment rules
pci 0000:06:08.0: bridge window [mem 0x01000000-0x057fffff] to [bus 0c-14] requires relaxed alignment rules
pci 0000:06:08.0: bridge window [mem 0x01000000-0x057fffff] to [bus 0c-14] requires relaxed alignment rules
pci 0000:06:08.0: bridge window [mem 0x01000000-0x057fffff] to [bus 0c-14] add_size 100000 add_align 1000000
pci 0000:06:0c.0: bridge window [mem 0x00100000-0x001fffff] to [bus 15] requires relaxed alignment rules
pci 0000:06:0d.0: bridge window [mem 0x00100000-0x001fffff] to [bus 16] requires relaxed alignment rules
pci 0000:06:0d.0: bridge window [mem 0x00100000-0x001fffff] to [bus 16] requires relaxed alignment rules
pci 0000:05:00.0: bridge window [mem 0xd4800000-0xd97fffff]: assigned
pci 0000:05:00.0: bridge window [mem 0x1060000000-0x10607fffff 64bit pref]: assigned
pci 0000:06:08.0: bridge window [mem size 0x04900000]: can't assign; no space
pci 0000:06:08.0: bridge window [mem size 0x04900000]: failed to assign
While this bug itself seems old, it has likely become more visible
after the relaxed tail alignment that does not grossly overestimate the
size needed for the bridge window.
Make sure add_align > min_align too results in adding an entry into the
realloc head list. In addition, add handling to the cases where
add_size is zero while only alignment differs.
Fixes: d74b9027a4da ("PCI: Consider additional PF's IOV BAR alignment in sizing and assigning")
Reported-by: Malte Schröder <malte+lkml@tnxip.de>
Tested-by: Malte Schröder <malte+lkml@tnxip.de>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Cc: stable@vger.kernel.org
---
drivers/pci/setup-bus.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 6e90f46f52af..4b918ff4d2d8 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -14,6 +14,7 @@
* tighter packing. Prefetchable range support.
*/
+#include <linux/align.h>
#include <linux/bitops.h>
#include <linux/bug.h>
#include <linux/init.h>
@@ -456,7 +457,7 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
"%s %pR: ignoring failure in optional allocation\n",
res_name, res);
}
- } else if (add_size > 0) {
+ } else if (add_size > 0 || !IS_ALIGNED(res->start, align)) {
res->flags |= add_res->flags &
(IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
if (pci_reassign_resource(dev, idx, add_size, align))
@@ -1442,12 +1443,13 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
resource_set_range(b_res, min_align, size0);
b_res->flags |= IORESOURCE_STARTALIGN;
- if (bus->self && size1 > size0 && realloc_head) {
+ if (bus->self && realloc_head && (size1 > size0 || add_align > min_align)) {
b_res->flags &= ~IORESOURCE_DISABLED;
- add_to_list(realloc_head, bus->self, b_res, size1-size0, add_align);
+ add_size = size1 > size0 ? size1 - size0 : 0;
+ add_to_list(realloc_head, bus->self, b_res, add_size, add_align);
pci_info(bus->self, "bridge window %pR to %pR add_size %llx add_align %llx\n",
b_res, &bus->busn_res,
- (unsigned long long) (size1 - size0),
+ (unsigned long long) add_size,
(unsigned long long) add_align);
}
}
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH 02/23] PCI: Rewrite bridge window head alignment function
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 01/23] PCI: Fix bridge window alignment with optional resources Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2026-01-26 22:17 ` Bjorn Helgaas
2025-12-19 17:40 ` [PATCH 03/23] PCI: Stop over-estimating bridge window size Ilpo Järvinen
` (21 subsequent siblings)
23 siblings, 1 reply; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen, Malte Schröder, stable
The calculation of bridge window head alignment is done by
calculate_mem_align() [*]. With the default bridge window alignment, it
is used for both head and tail alignment.
The selected head alignment does not always result in tight-fitting
resources (gap at d4f00000-d4ffffff):
d4800000-dbffffff : PCI Bus 0000:06
d4800000-d48fffff : PCI Bus 0000:07
d4800000-d4803fff : 0000:07:00.0
d4800000-d4803fff : nvme
d4900000-d49fffff : PCI Bus 0000:0a
d4900000-d490ffff : 0000:0a:00.0
d4900000-d490ffff : r8169
d4910000-d4913fff : 0000:0a:00.0
d4a00000-d4cfffff : PCI Bus 0000:0b
d4a00000-d4bfffff : 0000:0b:00.0
d4a00000-d4bfffff : 0000:0b:00.0
d4c00000-d4c07fff : 0000:0b:00.0
d4d00000-d4dfffff : PCI Bus 0000:15
d4d00000-d4d07fff : 0000:15:00.0
d4d00000-d4d07fff : xhci-hcd
d4e00000-d4efffff : PCI Bus 0000:16
d4e00000-d4e7ffff : 0000:16:00.0
d4e80000-d4e803ff : 0000:16:00.0
d4e80000-d4e803ff : ahci
d5000000-dbffffff : PCI Bus 0000:0c
This has not been caused problems (for years) with the default bridge
window tail alignment that grossly over-estimates the required tail
alignment leaving more tail room than necessary. With the introduction
of relaxed tail alignment that leaves no extra tail room whatsoever,
any gaps will immediately turn into assignment failures.
Introduce head alignment calculation that ensures no gaps are left and
apply the new approach when using relaxed alignment. We may want to
consider using it for the normal alignment eventually, but as the first
step, solve only the problem with the relaxed tail alignment.
([*] I don't understand the algorithm in calculate_mem_align().)
Fixes: 5d0a8965aea9 ("[PATCH] 2.5.14: New PCI allocation code (alpha, arm, parisc) [2/2]")
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220775
Reported-by: Malte Schröder <malte+lkml@tnxip.de>
Tested-by: Malte Schröder <malte+lkml@tnxip.de>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Cc: stable@vger.kernel.org
---
Little annoyingly, there's difference in what aligns array contains
between the legacy alignment approach (which I dare not to touch as I
really don't understand what the algorithm tries to do) and this new
head aligment algorithm, both consuming stack space. After making the
new approach the only available approach in the follow-up patch, only
one array remains (however, that follow-up change is also somewhat
riskier when it comes to regressions).
That being said, the new head alignment could work with the same aligns
array as the legacy approach, it just won't necessarily produce an
optimal (the smallest possible) head alignment when if (r_size <=
align) condition is used. Just let me know if that approach is
preferred (to save some stack space).
---
drivers/pci/setup-bus.c | 53 ++++++++++++++++++++++++++++++++++-------
1 file changed, 44 insertions(+), 9 deletions(-)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 4b918ff4d2d8..80e5a8fc62e7 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -1228,6 +1228,45 @@ static inline resource_size_t calculate_mem_align(resource_size_t *aligns,
return min_align;
}
+/*
+ * Calculate bridge window head alignment that leaves no gaps in between
+ * resources.
+ */
+static resource_size_t calculate_head_align(resource_size_t *aligns,
+ int max_order)
+{
+ resource_size_t head_align = 1;
+ resource_size_t remainder = 0;
+ int order;
+
+ /* Take the largest alignment as the starting point. */
+ head_align <<= max_order + __ffs(SZ_1M);
+
+ for (order = max_order - 1; order >= 0; order--) {
+ resource_size_t align1 = 1;
+
+ align1 <<= order + __ffs(SZ_1M);
+
+ /*
+ * Account smaller resources with alignment < max_order that
+ * could be used to fill head room if alignment less than
+ * max_order is used.
+ */
+ remainder += aligns[order];
+
+ /*
+ * Test if head fill is enough to satisfy the alignment of
+ * the larger resources after reducing the alignment.
+ */
+ while ((head_align > align1) && (remainder >= head_align / 2)) {
+ head_align /= 2;
+ remainder -= head_align;
+ }
+ }
+
+ return head_align;
+}
+
/**
* pbus_upstream_space_available - Check no upstream resource limits allocation
* @bus: The bus
@@ -1315,13 +1354,13 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
{
struct pci_dev *dev;
resource_size_t min_align, win_align, align, size, size0, size1 = 0;
- resource_size_t aligns[28]; /* Alignments from 1MB to 128TB */
+ resource_size_t aligns[28] = {}; /* Alignments from 1MB to 128TB */
+ resource_size_t aligns2[28] = {};/* Alignments from 1MB to 128TB */
int order, max_order;
struct resource *b_res = pbus_select_window_for_type(bus, type);
resource_size_t children_add_size = 0;
resource_size_t children_add_align = 0;
resource_size_t add_align = 0;
- resource_size_t relaxed_align;
resource_size_t old_size;
if (!b_res)
@@ -1331,7 +1370,6 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
if (b_res->parent)
return;
- memset(aligns, 0, sizeof(aligns));
max_order = 0;
size = 0;
@@ -1382,6 +1420,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
*/
if (r_size <= align)
aligns[order] += align;
+ aligns2[order] += align;
if (order > max_order)
max_order = order;
@@ -1406,9 +1445,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
if (bus->self && size0 &&
!pbus_upstream_space_available(bus, b_res, size0, min_align)) {
- relaxed_align = 1ULL << (max_order + __ffs(SZ_1M));
- relaxed_align = max(relaxed_align, win_align);
- min_align = min(min_align, relaxed_align);
+ min_align = calculate_head_align(aligns2, max_order);
size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align);
resource_set_range(b_res, min_align, size0);
pci_info(bus->self, "bridge window %pR to %pR requires relaxed alignment rules\n",
@@ -1422,9 +1459,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
if (bus->self && size1 &&
!pbus_upstream_space_available(bus, b_res, size1, add_align)) {
- relaxed_align = 1ULL << (max_order + __ffs(SZ_1M));
- relaxed_align = max(relaxed_align, win_align);
- min_align = min(min_align, relaxed_align);
+ min_align = calculate_head_align(aligns2, max_order);
size1 = calculate_memsize(size, min_size, add_size, children_add_size,
old_size, win_align);
pci_info(bus->self,
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH 02/23] PCI: Rewrite bridge window head alignment function
2025-12-19 17:40 ` [PATCH 02/23] PCI: Rewrite bridge window head alignment function Ilpo Järvinen
@ 2026-01-26 22:17 ` Bjorn Helgaas
2026-01-27 11:22 ` Ilpo Järvinen
0 siblings, 1 reply; 36+ messages in thread
From: Bjorn Helgaas @ 2026-01-26 22:17 UTC (permalink / raw)
To: Ilpo Järvinen
Cc: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel,
Malte Schröder, stable
On Fri, Dec 19, 2025 at 07:40:15PM +0200, Ilpo Järvinen wrote:
> The calculation of bridge window head alignment is done by
> calculate_mem_align() [*]. With the default bridge window alignment, it
> is used for both head and tail alignment.
>
> The selected head alignment does not always result in tight-fitting
> resources (gap at d4f00000-d4ffffff):
>
> d4800000-dbffffff : PCI Bus 0000:06
> d4800000-d48fffff : PCI Bus 0000:07
> d4800000-d4803fff : 0000:07:00.0
> d4800000-d4803fff : nvme
> d4900000-d49fffff : PCI Bus 0000:0a
> d4900000-d490ffff : 0000:0a:00.0
> d4900000-d490ffff : r8169
> d4910000-d4913fff : 0000:0a:00.0
> d4a00000-d4cfffff : PCI Bus 0000:0b
> d4a00000-d4bfffff : 0000:0b:00.0
> d4a00000-d4bfffff : 0000:0b:00.0
> d4c00000-d4c07fff : 0000:0b:00.0
> d4d00000-d4dfffff : PCI Bus 0000:15
> d4d00000-d4d07fff : 0000:15:00.0
> d4d00000-d4d07fff : xhci-hcd
> d4e00000-d4efffff : PCI Bus 0000:16
> d4e00000-d4e7ffff : 0000:16:00.0
> d4e80000-d4e803ff : 0000:16:00.0
> d4e80000-d4e803ff : ahci
> d5000000-dbffffff : PCI Bus 0000:0c
>
> This has not been caused problems (for years) with the default bridge
> window tail alignment that grossly over-estimates the required tail
> alignment leaving more tail room than necessary. With the introduction
> of relaxed tail alignment that leaves no extra tail room whatsoever,
> any gaps will immediately turn into assignment failures.
>
> Introduce head alignment calculation that ensures no gaps are left and
> apply the new approach when using relaxed alignment. We may want to
> consider using it for the normal alignment eventually, but as the first
> step, solve only the problem with the relaxed tail alignment.
>
> ([*] I don't understand the algorithm in calculate_mem_align().)
>
> Fixes: 5d0a8965aea9 ("[PATCH] 2.5.14: New PCI allocation code (alpha, arm, parisc) [2/2]")
check_commits complains that this SHA1 doesn't exist:
In commit
a21a27a0e893 ("PCI: Rewrite bridge window head alignment function")
Fixes tag
Fixes: 5d0a8965aea9 ("[PATCH] 2.5.14: New PCI allocation code (alpha, arm, parisc) [2/2]")
has these problem(s):
- Target SHA1 does not exist
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5d0a8965aea9
does find it, but says it's not reachable.
It's so old (2002) that I'm not sure it's worth including it as a
Fixes: tag.
Bjorn
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH 02/23] PCI: Rewrite bridge window head alignment function
2026-01-26 22:17 ` Bjorn Helgaas
@ 2026-01-27 11:22 ` Ilpo Järvinen
2026-01-27 22:39 ` Bjorn Helgaas
0 siblings, 1 reply; 36+ messages in thread
From: Ilpo Järvinen @ 2026-01-27 11:22 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: linux-pci, Bjorn Helgaas, Dominik Brodowski, LKML,
Malte Schröder, stable
[-- Attachment #1: Type: text/plain, Size: 3850 bytes --]
On Mon, 26 Jan 2026, Bjorn Helgaas wrote:
> On Fri, Dec 19, 2025 at 07:40:15PM +0200, Ilpo Järvinen wrote:
> > The calculation of bridge window head alignment is done by
> > calculate_mem_align() [*]. With the default bridge window alignment, it
> > is used for both head and tail alignment.
> >
> > The selected head alignment does not always result in tight-fitting
> > resources (gap at d4f00000-d4ffffff):
> >
> > d4800000-dbffffff : PCI Bus 0000:06
> > d4800000-d48fffff : PCI Bus 0000:07
> > d4800000-d4803fff : 0000:07:00.0
> > d4800000-d4803fff : nvme
> > d4900000-d49fffff : PCI Bus 0000:0a
> > d4900000-d490ffff : 0000:0a:00.0
> > d4900000-d490ffff : r8169
> > d4910000-d4913fff : 0000:0a:00.0
> > d4a00000-d4cfffff : PCI Bus 0000:0b
> > d4a00000-d4bfffff : 0000:0b:00.0
> > d4a00000-d4bfffff : 0000:0b:00.0
> > d4c00000-d4c07fff : 0000:0b:00.0
> > d4d00000-d4dfffff : PCI Bus 0000:15
> > d4d00000-d4d07fff : 0000:15:00.0
> > d4d00000-d4d07fff : xhci-hcd
> > d4e00000-d4efffff : PCI Bus 0000:16
> > d4e00000-d4e7ffff : 0000:16:00.0
> > d4e80000-d4e803ff : 0000:16:00.0
> > d4e80000-d4e803ff : ahci
> > d5000000-dbffffff : PCI Bus 0000:0c
> >
> > This has not been caused problems (for years) with the default bridge
> > window tail alignment that grossly over-estimates the required tail
> > alignment leaving more tail room than necessary. With the introduction
> > of relaxed tail alignment that leaves no extra tail room whatsoever,
> > any gaps will immediately turn into assignment failures.
> >
> > Introduce head alignment calculation that ensures no gaps are left and
> > apply the new approach when using relaxed alignment. We may want to
> > consider using it for the normal alignment eventually, but as the first
> > step, solve only the problem with the relaxed tail alignment.
> >
> > ([*] I don't understand the algorithm in calculate_mem_align().)
> >
> > Fixes: 5d0a8965aea9 ("[PATCH] 2.5.14: New PCI allocation code (alpha, arm, parisc) [2/2]")
>
> check_commits complains that this SHA1 doesn't exist:
>
> In commit
>
> a21a27a0e893 ("PCI: Rewrite bridge window head alignment function")
>
> Fixes tag
>
> Fixes: 5d0a8965aea9 ("[PATCH] 2.5.14: New PCI allocation code (alpha, arm, parisc) [2/2]")
>
> has these problem(s):
>
> - Target SHA1 does not exist
>
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5d0a8965aea9
> does find it, but says it's not reachable.
>
> It's so old (2002) that I'm not sure it's worth including it as a
> Fixes: tag.
Hi,
The commit is in the history repo, and yes, even the git web ui for some
reason says it's not reachable by any branch:
https://git.kernel.org/pub/scm/linux/kernel/git/history/history.git/commit/?id=5d0a8965aea93bd799ebcd671e562d90f3ec2711
...But it's part of a tag for sure:
$ git describe --contains 5d0a8965aea93bd799ebcd671e562d90f3ec2711
v2.5.15~11^2~5^2~10
The composition in the history repo is strange, things don't always appear
properly linear for some reason there but I've found that commit by going
backwards with git annotate code-line-shaid^ in a "loop" until I came
back to commit that introduced it. Maybe this entire lineage of commits is
headed only by a tag, dunno.
Many things in the resource fitting and assignment algorithm lead back to
that same commit BTW (and its commit message isn't very helpful in
explaining why things were made the way they were).
If you don't want to put it into a Fixes tag, could you put that history
repo URL into a Link tag instead. I do find it relevant where this came
from.
--
i.
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH 02/23] PCI: Rewrite bridge window head alignment function
2026-01-27 11:22 ` Ilpo Järvinen
@ 2026-01-27 22:39 ` Bjorn Helgaas
0 siblings, 0 replies; 36+ messages in thread
From: Bjorn Helgaas @ 2026-01-27 22:39 UTC (permalink / raw)
To: Ilpo Järvinen
Cc: linux-pci, Bjorn Helgaas, Dominik Brodowski, LKML,
Malte Schröder, stable
On Tue, Jan 27, 2026 at 01:22:22PM +0200, Ilpo Järvinen wrote:
> On Mon, 26 Jan 2026, Bjorn Helgaas wrote:
> > On Fri, Dec 19, 2025 at 07:40:15PM +0200, Ilpo Järvinen wrote:
> > > The calculation of bridge window head alignment is done by
> > > calculate_mem_align() [*]. With the default bridge window alignment, it
> > > is used for both head and tail alignment.
> ...
> > > Fixes: 5d0a8965aea9 ("[PATCH] 2.5.14: New PCI allocation code (alpha, arm, parisc) [2/2]")
> >
> > check_commits complains that this SHA1 doesn't exist:
> >
> > In commit
> >
> > a21a27a0e893 ("PCI: Rewrite bridge window head alignment function")
> >
> > Fixes tag
> >
> > Fixes: 5d0a8965aea9 ("[PATCH] 2.5.14: New PCI allocation code (alpha, arm, parisc) [2/2]")
> >
> > has these problem(s):
> >
> > - Target SHA1 does not exist
> >
> > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5d0a8965aea9
> > does find it, but says it's not reachable.
> >
> > It's so old (2002) that I'm not sure it's worth including it as a
> > Fixes: tag.
>
> Hi,
>
> The commit is in the history repo, and yes, even the git web ui for some
> reason says it's not reachable by any branch:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/history/history.git/commit/?id=5d0a8965aea93bd799ebcd671e562d90f3ec2711
>
> ...But it's part of a tag for sure:
>
> $ git describe --contains 5d0a8965aea93bd799ebcd671e562d90f3ec2711
> v2.5.15~11^2~5^2~10
Thanks, I made it a Link tag instead:
Link: https://git.kernel.org/history/history/c/5d0a8965aea9 ("[PATCH] 2.5.14: New PCI allocation code (alpha, arm, parisc) [2/2]")
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH 03/23] PCI: Stop over-estimating bridge window size
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 01/23] PCI: Fix bridge window alignment with optional resources Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 02/23] PCI: Rewrite bridge window head alignment function Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2026-03-05 15:13 ` Guenter Roeck
2025-12-19 17:40 ` [PATCH 04/23] resource: Increase MAX_IORES_LEVEL to 8 Ilpo Järvinen
` (20 subsequent siblings)
23 siblings, 1 reply; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen, Malte Schröder
New way to calculate the bridge window head alignment produces
tight-fit, that is, it does not leave any gaps between the resources.
Similarly, relaxed tail alignment does not leave extra tail room.
Start to use bridge window calculation that does not over-estimate
the size of the required window.
pbus_upstream_space_available() can be removed.
Tested-by: Malte Schröder <malte+lkml@tnxip.de>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/pci/setup-bus.c | 97 +++--------------------------------------
1 file changed, 5 insertions(+), 92 deletions(-)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 80e5a8fc62e7..612288716ba8 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -1267,68 +1267,6 @@ static resource_size_t calculate_head_align(resource_size_t *aligns,
return head_align;
}
-/**
- * pbus_upstream_space_available - Check no upstream resource limits allocation
- * @bus: The bus
- * @res: The resource to help select the correct bridge window
- * @size: The size required from the bridge window
- * @align: Required alignment for the resource
- *
- * Check that @size can fit inside the upstream bridge resources that are
- * already assigned. Select the upstream bridge window based on the type of
- * @res.
- *
- * Return: %true if enough space is available on all assigned upstream
- * resources.
- */
-static bool pbus_upstream_space_available(struct pci_bus *bus,
- struct resource *res,
- resource_size_t size,
- resource_size_t align)
-{
- struct resource_constraint constraint = {
- .max = RESOURCE_SIZE_MAX,
- .align = align,
- };
- struct pci_bus *downstream = bus;
-
- while ((bus = bus->parent)) {
- if (pci_is_root_bus(bus))
- break;
-
- res = pbus_select_window(bus, res);
- if (!res)
- return false;
- if (!res->parent)
- continue;
-
- if (resource_size(res) >= size) {
- struct resource gap = {};
-
- if (find_resource_space(res, &gap, size, &constraint) == 0) {
- gap.flags = res->flags;
- pci_dbg(bus->self,
- "Assigned bridge window %pR to %pR free space at %pR\n",
- res, &bus->busn_res, &gap);
- return true;
- }
- }
-
- if (bus->self) {
- pci_info(bus->self,
- "Assigned bridge window %pR to %pR cannot fit 0x%llx required for %s bridging to %pR\n",
- res, &bus->busn_res,
- (unsigned long long)size,
- pci_name(downstream->self),
- &downstream->busn_res);
- }
-
- return false;
- }
-
- return true;
-}
-
/**
* pbus_size_mem() - Size the memory window of a given bus
*
@@ -1355,7 +1293,6 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
struct pci_dev *dev;
resource_size_t min_align, win_align, align, size, size0, size1 = 0;
resource_size_t aligns[28] = {}; /* Alignments from 1MB to 128TB */
- resource_size_t aligns2[28] = {};/* Alignments from 1MB to 128TB */
int order, max_order;
struct resource *b_res = pbus_select_window_for_type(bus, type);
resource_size_t children_add_size = 0;
@@ -1414,13 +1351,8 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
continue;
}
size += max(r_size, align);
- /*
- * Exclude ranges with size > align from calculation of
- * the alignment.
- */
- if (r_size <= align)
- aligns[order] += align;
- aligns2[order] += align;
+
+ aligns[order] += align;
if (order > max_order)
max_order = order;
@@ -1434,38 +1366,19 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
old_size = resource_size(b_res);
win_align = window_alignment(bus, b_res->flags);
- min_align = calculate_mem_align(aligns, max_order);
+ min_align = calculate_head_align(aligns, max_order);
min_align = max(min_align, win_align);
- size0 = calculate_memsize(size, min_size, 0, 0, old_size, min_align);
+ size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align);
if (size0) {
resource_set_range(b_res, min_align, size0);
b_res->flags &= ~IORESOURCE_DISABLED;
}
- if (bus->self && size0 &&
- !pbus_upstream_space_available(bus, b_res, size0, min_align)) {
- min_align = calculate_head_align(aligns2, max_order);
- size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align);
- resource_set_range(b_res, min_align, size0);
- pci_info(bus->self, "bridge window %pR to %pR requires relaxed alignment rules\n",
- b_res, &bus->busn_res);
- }
-
if (realloc_head && (add_size > 0 || children_add_size > 0)) {
add_align = max(min_align, add_align);
size1 = calculate_memsize(size, min_size, add_size, children_add_size,
- old_size, add_align);
-
- if (bus->self && size1 &&
- !pbus_upstream_space_available(bus, b_res, size1, add_align)) {
- min_align = calculate_head_align(aligns2, max_order);
- size1 = calculate_memsize(size, min_size, add_size, children_add_size,
- old_size, win_align);
- pci_info(bus->self,
- "bridge window %pR to %pR requires relaxed alignment rules\n",
- b_res, &bus->busn_res);
- }
+ old_size, win_align);
}
if (!size0 && !size1) {
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH 03/23] PCI: Stop over-estimating bridge window size
2025-12-19 17:40 ` [PATCH 03/23] PCI: Stop over-estimating bridge window size Ilpo Järvinen
@ 2026-03-05 15:13 ` Guenter Roeck
2026-03-05 16:28 ` Ilpo Järvinen
0 siblings, 1 reply; 36+ messages in thread
From: Guenter Roeck @ 2026-03-05 15:13 UTC (permalink / raw)
To: Ilpo Järvinen
Cc: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel,
Malte Schröder
Hi,
On Fri, Dec 19, 2025 at 07:40:16PM +0200, Ilpo Järvinen wrote:
> New way to calculate the bridge window head alignment produces
> tight-fit, that is, it does not leave any gaps between the resources.
> Similarly, relaxed tail alignment does not leave extra tail room.
>
> Start to use bridge window calculation that does not over-estimate
> the size of the required window.
>
> pbus_upstream_space_available() can be removed.
>
> Tested-by: Malte Schröder <malte+lkml@tnxip.de>
> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
> ---
Google's experimental AI code review agent produced the following feedback.
It seems real to me, but I may be missing something. PTAL and let me know
if it has a point.
If it is a real problem, it may have been fixed by a later patch which I
may have missed. If so, my apologies for the noise.
Thanks,
Guenter
---
commit 3958bf16e2fe1b1c95467e58694102122c951a31
Author: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
PCI: Stop over-estimating bridge window size
New way to calculate the bridge window head alignment produces tight-fit,
that is, it does not leave any gaps between the resources. Similarly,
relaxed tail alignment does not leave extra tail room.
Link: https://patch.msgid.link/20251219174036.16738-4-ilpo.jarvinen@linux.intel.com
> diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
> index cd12926a72af..25d6d4d3afc1 100644
> --- a/drivers/pci/setup-bus.c
> +++ b/drivers/pci/setup-bus.c
[ ... ]
> @@ -1409,13 +1346,8 @@
> continue;
> }
> size += max(r_size, align);
> - /*
> - * Exclude ranges with size > align from calculation of
> - * the alignment.
> - */
> - if (r_size <= align)
> - aligns[order] += align;
> - aligns2[order] += align;
> +
> + aligns[order] += align;
> if (order > max_order)
> max_order = order;
>
> @@ -1429,38 +1361,19 @@
>
> old_size = resource_size(b_res);
> win_align = window_alignment(bus, b_res->flags);
> - min_align = calculate_mem_align(aligns, max_order);
> + min_align = calculate_head_align(aligns, max_order);
> min_align = max(min_align, win_align);
> - size0 = calculate_memsize(size, min_size, 0, 0, old_size, min_align);
> + size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align);
Does the removal of the `r_size <= align` check cause bridge window size
underestimations if we have child resources larger than their alignment?
If we have child resources with the following requirements:
- Resource A: 4MB size, 4MB align
- Resource B: 3MB size, 1MB align
- Resource C: 1MB size, 1MB align
The requested `size` is calculated as 4 + 3 + 1 = 8MB.
`aligns[order]` for 1MB will now incorrectly include B, summing to 2MB.
`calculate_head_align()` will see the 2MB remainder and reduce `min_align`
to 2MB, assuming the remainder can perfectly fill a 2MB head gap.
If the bridge window of size 8MB is allocated at a 2MB-aligned address
(e.g., `0x10200000`), the 4MB aligned Resource A must be placed at
`0x10400000`, leaving a 2MB gap.
Resource B (3MB) cannot fit in this 2MB gap, so it is placed after A at
`0x10800000`.
Resource C (1MB) fits in the gap at `0x10200000`.
The total space used spans from `0x10200000` to `0x10AFFFFF` (9MB).
Since `size0` was calculated as 8MB, won't Resource B fail to allocate
because it exceeds the bridge window?
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH 03/23] PCI: Stop over-estimating bridge window size
2026-03-05 15:13 ` Guenter Roeck
@ 2026-03-05 16:28 ` Ilpo Järvinen
0 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2026-03-05 16:28 UTC (permalink / raw)
To: Guenter Roeck
Cc: linux-pci, Bjorn Helgaas, Dominik Brodowski, LKML,
Malte Schröder
[-- Attachment #1: Type: text/plain, Size: 4408 bytes --]
On Thu, 5 Mar 2026, Guenter Roeck wrote:
> On Fri, Dec 19, 2025 at 07:40:16PM +0200, Ilpo Järvinen wrote:
> > New way to calculate the bridge window head alignment produces
> > tight-fit, that is, it does not leave any gaps between the resources.
> > Similarly, relaxed tail alignment does not leave extra tail room.
> >
> > Start to use bridge window calculation that does not over-estimate
> > the size of the required window.
> >
> > pbus_upstream_space_available() can be removed.
> >
> > Tested-by: Malte Schröder <malte+lkml@tnxip.de>
> > Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
> > ---
>
> Google's experimental AI code review agent produced the following feedback.
> It seems real to me, but I may be missing something. PTAL and let me know
> if it has a point.
>
> If it is a real problem, it may have been fixed by a later patch which I
> may have missed. If so, my apologies for the noise.
Thanks. It looks a real problem to me.
> Thanks,
> Guenter
>
> ---
> commit 3958bf16e2fe1b1c95467e58694102122c951a31
> Author: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
>
> PCI: Stop over-estimating bridge window size
>
> New way to calculate the bridge window head alignment produces tight-fit,
> that is, it does not leave any gaps between the resources. Similarly,
> relaxed tail alignment does not leave extra tail room.
>
> Link: https://patch.msgid.link/20251219174036.16738-4-ilpo.jarvinen@linux.intel.com
>
> > diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
> > index cd12926a72af..25d6d4d3afc1 100644
> > --- a/drivers/pci/setup-bus.c
> > +++ b/drivers/pci/setup-bus.c
>
> [ ... ]
>
> > @@ -1409,13 +1346,8 @@
> > continue;
> > }
> > size += max(r_size, align);
> > - /*
> > - * Exclude ranges with size > align from calculation of
> > - * the alignment.
> > - */
> > - if (r_size <= align)
> > - aligns[order] += align;
> > - aligns2[order] += align;
> > +
> > + aligns[order] += align;
> > if (order > max_order)
> > max_order = order;
> >
> > @@ -1429,38 +1361,19 @@
> >
> > old_size = resource_size(b_res);
> > win_align = window_alignment(bus, b_res->flags);
> > - min_align = calculate_mem_align(aligns, max_order);
> > + min_align = calculate_head_align(aligns, max_order);
> > min_align = max(min_align, win_align);
> > - size0 = calculate_memsize(size, min_size, 0, 0, old_size, min_align);
> > + size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align);
>
> Does the removal of the `r_size <= align` check cause bridge window size
> underestimations if we have child resources larger than their alignment?
It's not really what I'd call underestimation but an unwanted gap what is
the end result here.
I'll think this over the weekend, maybe the best solution for now is to
put that check back. With the check, those resources will end up into tail
space more often but anything else I can think of would require more
complex data structures.
I'd eventually want to use better data structure anyway as I'd want to
make it possible to put as much stuff into the head side while still
producing gapless fit to generally produce tighter fit for windows that
are next to each other in the address space if both have resources
smaller than the max order.
> If we have child resources with the following requirements:
> - Resource A: 4MB size, 4MB align
> - Resource B: 3MB size, 1MB align
> - Resource C: 1MB size, 1MB align
>
> The requested `size` is calculated as 4 + 3 + 1 = 8MB.
> `aligns[order]` for 1MB will now incorrectly include B, summing to 2MB.
> `calculate_head_align()` will see the 2MB remainder and reduce `min_align`
> to 2MB, assuming the remainder can perfectly fill a 2MB head gap.
>
> If the bridge window of size 8MB is allocated at a 2MB-aligned address
> (e.g., `0x10200000`), the 4MB aligned Resource A must be placed at
> `0x10400000`, leaving a 2MB gap.
>
> Resource B (3MB) cannot fit in this 2MB gap, so it is placed after A at
> `0x10800000`.
> Resource C (1MB) fits in the gap at `0x10200000`.
>
> The total space used spans from `0x10200000` to `0x10AFFFFF` (9MB).
> Since `size0` was calculated as 8MB, won't Resource B fail to allocate
> because it exceeds the bridge window?
>
--
i.
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH 04/23] resource: Increase MAX_IORES_LEVEL to 8
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (2 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 03/23] PCI: Stop over-estimating bridge window size Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 05/23] PCI: Remove old_size limit from bridge window sizing Ilpo Järvinen
` (19 subsequent siblings)
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
While debugging a PCI resource allocation issue, the resources for many
nested bridges and endpoints got flattened in /proc/iomem by
MAX_IORES_LEVEL that is set to 5. This made the iomem output hard to
read as the visual hierarchy cues were lost.
Increase MAX_IORES_LEVEL to 8 to avoid flattening PCI topologies with
nested bridges so aggressively (the case in the Link has the deepest
resource at level 7 so 8 looks a reasonable limit).
Link: https://bugzilla.kernel.org/show_bug.cgi?id=220775
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
kernel/resource.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/resource.c b/kernel/resource.c
index e4e9bac12e6e..c5f03ac78e44 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -82,7 +82,7 @@ static struct resource *next_resource(struct resource *p, bool skip_children,
#ifdef CONFIG_PROC_FS
-enum { MAX_IORES_LEVEL = 5 };
+enum { MAX_IORES_LEVEL = 8 };
static void *r_start(struct seq_file *m, loff_t *pos)
__acquires(resource_lock)
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH 05/23] PCI: Remove old_size limit from bridge window sizing
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (3 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 04/23] resource: Increase MAX_IORES_LEVEL to 8 Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2026-01-26 17:16 ` Bjorn Helgaas
2025-12-19 17:40 ` [PATCH 06/23] PCI: Push realloc check into pbus_size_mem() Ilpo Järvinen
` (18 subsequent siblings)
23 siblings, 1 reply; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, Ilpo Järvinen,
linux-kernel
Cc: Simon Richter
calculate_memsize() applies lower bound to the resource size before
aligning the resource size making it impossible to shrink bridge window
resources. I've not found any justification for this lower bound and
nothing indicated it was to work around some HW issue.
Prior to the commit 3baeae36039a ("PCI: Use pci_release_resource()
instead of release_resource()"), releasing a bridge window during BAR
resize resulted in clearing start and end address of the resource.
Clearing addresses destroys the resource size as a side-effect,
therefore nullifying the effect of the old size lower bound.
After the commit 3baeae36039a ("PCI: Use pci_release_resource() instead
of release_resource()"), BAR resize uses the aligned old size, which
results in exceeding what fits into the parent window in some cases:
xe 0030:03:00.0: [drm] Attempting to resize bar from 256MiB -> 16384MiB
xe 0030:03:00.0: BAR 0 [mem 0x620c000000000-0x620c000ffffff 64bit]: releasing
xe 0030:03:00.0: BAR 2 [mem 0x6200000000000-0x620000fffffff 64bit pref]: releasing
pci 0030:02:01.0: bridge window [mem 0x6200000000000-0x620001fffffff 64bit pref]: releasing
pci 0030:01:00.0: bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref]: releasing
pci 0030:00:00.0: bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref]: was not released (still contains assigned resources)
pci 0030:00:00.0: Assigned bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref] to [bus 01-04] free space at [mem 0x6200400000000-0x62007ffffffff 64bit pref]
pci 0030:00:00.0: Assigned bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref] to [bus 01-04] cannot fit 0x4000000000 required for 0030:01:00.0 bridging to [bus 02-04]
The old size of 0x6200000000000-0x6203fbff0ffff resource was used as
the lower bound which results in 0x4000000000 size request due to
alignment. That exceed what can fit into the parent window.
Since the lower bound never even was enforced fully because the
resource addresses were cleared when the bridge window is released,
remove the old_size lower bound entirely and trust the calculated
bridge window size is enough.
This same problem may occur on io window side but seems less likely to
cause issues due to general difference in alignment. Removing the lower
bound may have other unforeseen consequences in case of io window so
it's better to do leave as -next material if no problem is reported
related to io window sizing (BAR resize shouldn't touch io windows
anyway).
Reported-by: Simon Richter <Simon.Richter@hogyros.de>
Fixes: 3baeae36039a ("PCI: Use pci_release_resource() instead of release_resource()")
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/pci/setup-bus.c | 11 +++--------
1 file changed, 3 insertions(+), 8 deletions(-)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 612288716ba8..8660449f59bd 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -1071,16 +1071,13 @@ static resource_size_t calculate_memsize(resource_size_t size,
resource_size_t min_size,
resource_size_t add_size,
resource_size_t children_add_size,
- resource_size_t old_size,
resource_size_t align)
{
if (size < min_size)
size = min_size;
- if (old_size == 1)
- old_size = 0;
size = max(size, add_size) + children_add_size;
- return ALIGN(max(size, old_size), align);
+ return ALIGN(size, align);
}
resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus,
@@ -1298,7 +1295,6 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
resource_size_t children_add_size = 0;
resource_size_t children_add_align = 0;
resource_size_t add_align = 0;
- resource_size_t old_size;
if (!b_res)
return;
@@ -1364,11 +1360,10 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
}
}
- old_size = resource_size(b_res);
win_align = window_alignment(bus, b_res->flags);
min_align = calculate_head_align(aligns, max_order);
min_align = max(min_align, win_align);
- size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align);
+ size0 = calculate_memsize(size, min_size, 0, 0, win_align);
if (size0) {
resource_set_range(b_res, min_align, size0);
@@ -1378,7 +1373,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
if (realloc_head && (add_size > 0 || children_add_size > 0)) {
add_align = max(min_align, add_align);
size1 = calculate_memsize(size, min_size, add_size, children_add_size,
- old_size, win_align);
+ win_align);
}
if (!size0 && !size1) {
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH 05/23] PCI: Remove old_size limit from bridge window sizing
2025-12-19 17:40 ` [PATCH 05/23] PCI: Remove old_size limit from bridge window sizing Ilpo Järvinen
@ 2026-01-26 17:16 ` Bjorn Helgaas
2026-01-26 20:09 ` Bjorn Helgaas
2026-01-27 10:16 ` Ilpo Järvinen
0 siblings, 2 replies; 36+ messages in thread
From: Bjorn Helgaas @ 2026-01-26 17:16 UTC (permalink / raw)
To: Ilpo Järvinen
Cc: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel,
Simon Richter
On Fri, Dec 19, 2025 at 07:40:18PM +0200, Ilpo Järvinen wrote:
> calculate_memsize() applies lower bound to the resource size before
> aligning the resource size making it impossible to shrink bridge window
> resources. I've not found any justification for this lower bound and
> nothing indicated it was to work around some HW issue.
>
> Prior to the commit 3baeae36039a ("PCI: Use pci_release_resource()
> instead of release_resource()"), releasing a bridge window during BAR
> resize resulted in clearing start and end address of the resource.
> Clearing addresses destroys the resource size as a side-effect,
> therefore nullifying the effect of the old size lower bound.
>
> After the commit 3baeae36039a ("PCI: Use pci_release_resource() instead
> of release_resource()"), BAR resize uses the aligned old size, which
> results in exceeding what fits into the parent window in some cases:
>
> xe 0030:03:00.0: [drm] Attempting to resize bar from 256MiB -> 16384MiB
> xe 0030:03:00.0: BAR 0 [mem 0x620c000000000-0x620c000ffffff 64bit]: releasing
> xe 0030:03:00.0: BAR 2 [mem 0x6200000000000-0x620000fffffff 64bit pref]: releasing
> pci 0030:02:01.0: bridge window [mem 0x6200000000000-0x620001fffffff 64bit pref]: releasing
> pci 0030:01:00.0: bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref]: releasing
> pci 0030:00:00.0: bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref]: was not released (still contains assigned resources)
> pci 0030:00:00.0: Assigned bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref] to [bus 01-04] free space at [mem 0x6200400000000-0x62007ffffffff 64bit pref]
> pci 0030:00:00.0: Assigned bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref] to [bus 01-04] cannot fit 0x4000000000 required for 0030:01:00.0 bridging to [bus 02-04]
>
> The old size of 0x6200000000000-0x6203fbff0ffff resource was used as
> the lower bound which results in 0x4000000000 size request due to
> alignment. That exceed what can fit into the parent window.
>
> Since the lower bound never even was enforced fully because the
> resource addresses were cleared when the bridge window is released,
> remove the old_size lower bound entirely and trust the calculated
> bridge window size is enough.
>
> This same problem may occur on io window side but seems less likely to
> cause issues due to general difference in alignment. Removing the lower
> bound may have other unforeseen consequences in case of io window so
> it's better to do leave as -next material if no problem is reported
> related to io window sizing (BAR resize shouldn't touch io windows
> anyway).
>
> Reported-by: Simon Richter <Simon.Richter@hogyros.de>
I guess this report was
https://lore.kernel.org/r/f9a8c975-f5d3-4dd2-988e-4371a1433a60@hogyros.de/,
right?
> Fixes: 3baeae36039a ("PCI: Use pci_release_resource() instead of release_resource()")
> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
> ---
> drivers/pci/setup-bus.c | 11 +++--------
> 1 file changed, 3 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
> index 612288716ba8..8660449f59bd 100644
> --- a/drivers/pci/setup-bus.c
> +++ b/drivers/pci/setup-bus.c
> @@ -1071,16 +1071,13 @@ static resource_size_t calculate_memsize(resource_size_t size,
> resource_size_t min_size,
> resource_size_t add_size,
> resource_size_t children_add_size,
> - resource_size_t old_size,
> resource_size_t align)
> {
> if (size < min_size)
> size = min_size;
> - if (old_size == 1)
> - old_size = 0;
>
> size = max(size, add_size) + children_add_size;
> - return ALIGN(max(size, old_size), align);
> + return ALIGN(size, align);
> }
>
> resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus,
> @@ -1298,7 +1295,6 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
> resource_size_t children_add_size = 0;
> resource_size_t children_add_align = 0;
> resource_size_t add_align = 0;
> - resource_size_t old_size;
>
> if (!b_res)
> return;
> @@ -1364,11 +1360,10 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
> }
> }
>
> - old_size = resource_size(b_res);
> win_align = window_alignment(bus, b_res->flags);
> min_align = calculate_head_align(aligns, max_order);
> min_align = max(min_align, win_align);
> - size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align);
> + size0 = calculate_memsize(size, min_size, 0, 0, win_align);
>
> if (size0) {
> resource_set_range(b_res, min_align, size0);
> @@ -1378,7 +1373,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
> if (realloc_head && (add_size > 0 || children_add_size > 0)) {
> add_align = max(min_align, add_align);
> size1 = calculate_memsize(size, min_size, add_size, children_add_size,
> - old_size, win_align);
> + win_align);
> }
>
> if (!size0 && !size1) {
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH 05/23] PCI: Remove old_size limit from bridge window sizing
2026-01-26 17:16 ` Bjorn Helgaas
@ 2026-01-26 20:09 ` Bjorn Helgaas
2026-01-27 11:39 ` Ilpo Järvinen
2026-01-27 10:16 ` Ilpo Järvinen
1 sibling, 1 reply; 36+ messages in thread
From: Bjorn Helgaas @ 2026-01-26 20:09 UTC (permalink / raw)
To: Ilpo Järvinen
Cc: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel,
Simon Richter
On Mon, Jan 26, 2026 at 11:16:01AM -0600, Bjorn Helgaas wrote:
> On Fri, Dec 19, 2025 at 07:40:18PM +0200, Ilpo Järvinen wrote:
> > calculate_memsize() applies lower bound to the resource size before
> > aligning the resource size making it impossible to shrink bridge window
> > resources. I've not found any justification for this lower bound and
> > nothing indicated it was to work around some HW issue.
> >
> > Prior to the commit 3baeae36039a ("PCI: Use pci_release_resource()
> > instead of release_resource()"), releasing a bridge window during BAR
> > resize resulted in clearing start and end address of the resource.
> > Clearing addresses destroys the resource size as a side-effect,
> > therefore nullifying the effect of the old size lower bound.
> >
> > After the commit 3baeae36039a ("PCI: Use pci_release_resource() instead
> > of release_resource()"), BAR resize uses the aligned old size, which
> > results in exceeding what fits into the parent window in some cases:
> >
> > xe 0030:03:00.0: [drm] Attempting to resize bar from 256MiB -> 16384MiB
> > xe 0030:03:00.0: BAR 0 [mem 0x620c000000000-0x620c000ffffff 64bit]: releasing
> > xe 0030:03:00.0: BAR 2 [mem 0x6200000000000-0x620000fffffff 64bit pref]: releasing
> > pci 0030:02:01.0: bridge window [mem 0x6200000000000-0x620001fffffff 64bit pref]: releasing
> > pci 0030:01:00.0: bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref]: releasing
> > pci 0030:00:00.0: bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref]: was not released (still contains assigned resources)
> > pci 0030:00:00.0: Assigned bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref] to [bus 01-04] free space at [mem 0x6200400000000-0x62007ffffffff 64bit pref]
> > pci 0030:00:00.0: Assigned bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref] to [bus 01-04] cannot fit 0x4000000000 required for 0030:01:00.0 bridging to [bus 02-04]
> >
> > The old size of 0x6200000000000-0x6203fbff0ffff resource was used as
> > the lower bound which results in 0x4000000000 size request due to
> > alignment. That exceed what can fit into the parent window.
> >
> > Since the lower bound never even was enforced fully because the
> > resource addresses were cleared when the bridge window is released,
> > remove the old_size lower bound entirely and trust the calculated
> > bridge window size is enough.
> >
> > This same problem may occur on io window side but seems less likely to
> > cause issues due to general difference in alignment. Removing the lower
> > bound may have other unforeseen consequences in case of io window so
> > it's better to do leave as -next material if no problem is reported
> > related to io window sizing (BAR resize shouldn't touch io windows
> > anyway).
> >
> > Reported-by: Simon Richter <Simon.Richter@hogyros.de>
>
> I guess this report was
> https://lore.kernel.org/r/f9a8c975-f5d3-4dd2-988e-4371a1433a60@hogyros.de/,
> right?
And this looks like a regression in v6.18 that will persist in v6.19.
Is that the right thing? I wonder if we should move these first five
patches to pci/for-linus so they land in v6.19?
> > Fixes: 3baeae36039a ("PCI: Use pci_release_resource() instead of release_resource()")
> > Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
> > ---
> > drivers/pci/setup-bus.c | 11 +++--------
> > 1 file changed, 3 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
> > index 612288716ba8..8660449f59bd 100644
> > --- a/drivers/pci/setup-bus.c
> > +++ b/drivers/pci/setup-bus.c
> > @@ -1071,16 +1071,13 @@ static resource_size_t calculate_memsize(resource_size_t size,
> > resource_size_t min_size,
> > resource_size_t add_size,
> > resource_size_t children_add_size,
> > - resource_size_t old_size,
> > resource_size_t align)
> > {
> > if (size < min_size)
> > size = min_size;
> > - if (old_size == 1)
> > - old_size = 0;
> >
> > size = max(size, add_size) + children_add_size;
> > - return ALIGN(max(size, old_size), align);
> > + return ALIGN(size, align);
> > }
> >
> > resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus,
> > @@ -1298,7 +1295,6 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
> > resource_size_t children_add_size = 0;
> > resource_size_t children_add_align = 0;
> > resource_size_t add_align = 0;
> > - resource_size_t old_size;
> >
> > if (!b_res)
> > return;
> > @@ -1364,11 +1360,10 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
> > }
> > }
> >
> > - old_size = resource_size(b_res);
> > win_align = window_alignment(bus, b_res->flags);
> > min_align = calculate_head_align(aligns, max_order);
> > min_align = max(min_align, win_align);
> > - size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align);
> > + size0 = calculate_memsize(size, min_size, 0, 0, win_align);
> >
> > if (size0) {
> > resource_set_range(b_res, min_align, size0);
> > @@ -1378,7 +1373,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
> > if (realloc_head && (add_size > 0 || children_add_size > 0)) {
> > add_align = max(min_align, add_align);
> > size1 = calculate_memsize(size, min_size, add_size, children_add_size,
> > - old_size, win_align);
> > + win_align);
> > }
> >
> > if (!size0 && !size1) {
> > --
> > 2.39.5
> >
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH 05/23] PCI: Remove old_size limit from bridge window sizing
2026-01-26 20:09 ` Bjorn Helgaas
@ 2026-01-27 11:39 ` Ilpo Järvinen
2026-01-27 22:42 ` Bjorn Helgaas
0 siblings, 1 reply; 36+ messages in thread
From: Ilpo Järvinen @ 2026-01-27 11:39 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: linux-pci, Bjorn Helgaas, Dominik Brodowski, LKML, Simon Richter
[-- Attachment #1: Type: text/plain, Size: 6784 bytes --]
On Mon, 26 Jan 2026, Bjorn Helgaas wrote:
> On Mon, Jan 26, 2026 at 11:16:01AM -0600, Bjorn Helgaas wrote:
> > On Fri, Dec 19, 2025 at 07:40:18PM +0200, Ilpo Järvinen wrote:
> > > calculate_memsize() applies lower bound to the resource size before
> > > aligning the resource size making it impossible to shrink bridge window
> > > resources. I've not found any justification for this lower bound and
> > > nothing indicated it was to work around some HW issue.
> > >
> > > Prior to the commit 3baeae36039a ("PCI: Use pci_release_resource()
> > > instead of release_resource()"), releasing a bridge window during BAR
> > > resize resulted in clearing start and end address of the resource.
> > > Clearing addresses destroys the resource size as a side-effect,
> > > therefore nullifying the effect of the old size lower bound.
> > >
> > > After the commit 3baeae36039a ("PCI: Use pci_release_resource() instead
> > > of release_resource()"), BAR resize uses the aligned old size, which
> > > results in exceeding what fits into the parent window in some cases:
> > >
> > > xe 0030:03:00.0: [drm] Attempting to resize bar from 256MiB -> 16384MiB
> > > xe 0030:03:00.0: BAR 0 [mem 0x620c000000000-0x620c000ffffff 64bit]: releasing
> > > xe 0030:03:00.0: BAR 2 [mem 0x6200000000000-0x620000fffffff 64bit pref]: releasing
> > > pci 0030:02:01.0: bridge window [mem 0x6200000000000-0x620001fffffff 64bit pref]: releasing
> > > pci 0030:01:00.0: bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref]: releasing
> > > pci 0030:00:00.0: bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref]: was not released (still contains assigned resources)
> > > pci 0030:00:00.0: Assigned bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref] to [bus 01-04] free space at [mem 0x6200400000000-0x62007ffffffff 64bit pref]
> > > pci 0030:00:00.0: Assigned bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref] to [bus 01-04] cannot fit 0x4000000000 required for 0030:01:00.0 bridging to [bus 02-04]
> > >
> > > The old size of 0x6200000000000-0x6203fbff0ffff resource was used as
> > > the lower bound which results in 0x4000000000 size request due to
> > > alignment. That exceed what can fit into the parent window.
> > >
> > > Since the lower bound never even was enforced fully because the
> > > resource addresses were cleared when the bridge window is released,
> > > remove the old_size lower bound entirely and trust the calculated
> > > bridge window size is enough.
> > >
> > > This same problem may occur on io window side but seems less likely to
> > > cause issues due to general difference in alignment. Removing the lower
> > > bound may have other unforeseen consequences in case of io window so
> > > it's better to do leave as -next material if no problem is reported
> > > related to io window sizing (BAR resize shouldn't touch io windows
> > > anyway).
> > >
> > > Reported-by: Simon Richter <Simon.Richter@hogyros.de>
> >
> > I guess this report was
> > https://lore.kernel.org/r/f9a8c975-f5d3-4dd2-988e-4371a1433a60@hogyros.de/,
> > right?
>
> And this looks like a regression in v6.18 that will persist in v6.19.
>
> Is that the right thing? I wonder if we should move these first five
> patches to pci/for-linus so they land in v6.19?
Fine with me if you want to do that. Stable people would pick things that
landing in the merge window into Linus' tree anyway so the difference
isn't going to be that huge.
Patch 3 is the scariest of the changes and is not strictly even a fix
(without it there are two parallel alignment approaches though which
wastes some stack space). It will have some impact on resource allocation
when the new approach is enabled for everything were as previously the new
sizing/alignment approached were only used in the relative safe haven of
relaxed tail alignment cases; though in my tests, surprisingly few changes
did occur.
The patch 4 too is on the edge, if you want to push that through for-linus
(but it's not dangerous and is useful for complex topos).
I don't know how you are going to handle the pci/resource branch then
though as I expect the rest of the series to not apply cleanly without
those 5 patches.
--
i.
> > > Fixes: 3baeae36039a ("PCI: Use pci_release_resource() instead of release_resource()")
> > > Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
> > > ---
> > > drivers/pci/setup-bus.c | 11 +++--------
> > > 1 file changed, 3 insertions(+), 8 deletions(-)
> > >
> > > diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
> > > index 612288716ba8..8660449f59bd 100644
> > > --- a/drivers/pci/setup-bus.c
> > > +++ b/drivers/pci/setup-bus.c
> > > @@ -1071,16 +1071,13 @@ static resource_size_t calculate_memsize(resource_size_t size,
> > > resource_size_t min_size,
> > > resource_size_t add_size,
> > > resource_size_t children_add_size,
> > > - resource_size_t old_size,
> > > resource_size_t align)
> > > {
> > > if (size < min_size)
> > > size = min_size;
> > > - if (old_size == 1)
> > > - old_size = 0;
> > >
> > > size = max(size, add_size) + children_add_size;
> > > - return ALIGN(max(size, old_size), align);
> > > + return ALIGN(size, align);
> > > }
> > >
> > > resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus,
> > > @@ -1298,7 +1295,6 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
> > > resource_size_t children_add_size = 0;
> > > resource_size_t children_add_align = 0;
> > > resource_size_t add_align = 0;
> > > - resource_size_t old_size;
> > >
> > > if (!b_res)
> > > return;
> > > @@ -1364,11 +1360,10 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
> > > }
> > > }
> > >
> > > - old_size = resource_size(b_res);
> > > win_align = window_alignment(bus, b_res->flags);
> > > min_align = calculate_head_align(aligns, max_order);
> > > min_align = max(min_align, win_align);
> > > - size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align);
> > > + size0 = calculate_memsize(size, min_size, 0, 0, win_align);
> > >
> > > if (size0) {
> > > resource_set_range(b_res, min_align, size0);
> > > @@ -1378,7 +1373,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
> > > if (realloc_head && (add_size > 0 || children_add_size > 0)) {
> > > add_align = max(min_align, add_align);
> > > size1 = calculate_memsize(size, min_size, add_size, children_add_size,
> > > - old_size, win_align);
> > > + win_align);
> > > }
> > >
> > > if (!size0 && !size1) {
> > > --
> > > 2.39.5
> > >
>
^ permalink raw reply [flat|nested] 36+ messages in thread* Re: [PATCH 05/23] PCI: Remove old_size limit from bridge window sizing
2026-01-27 11:39 ` Ilpo Järvinen
@ 2026-01-27 22:42 ` Bjorn Helgaas
0 siblings, 0 replies; 36+ messages in thread
From: Bjorn Helgaas @ 2026-01-27 22:42 UTC (permalink / raw)
To: Ilpo Järvinen
Cc: linux-pci, Bjorn Helgaas, Dominik Brodowski, LKML, Simon Richter
On Tue, Jan 27, 2026 at 01:39:39PM +0200, Ilpo Järvinen wrote:
> On Mon, 26 Jan 2026, Bjorn Helgaas wrote:
> > On Mon, Jan 26, 2026 at 11:16:01AM -0600, Bjorn Helgaas wrote:
> > > On Fri, Dec 19, 2025 at 07:40:18PM +0200, Ilpo Järvinen wrote:
> > > > calculate_memsize() applies lower bound to the resource size before
> > > > aligning the resource size making it impossible to shrink bridge window
> > > > resources. I've not found any justification for this lower bound and
> > > > nothing indicated it was to work around some HW issue.
> ...
> > > > Reported-by: Simon Richter <Simon.Richter@hogyros.de>
> > >
> > > I guess this report was
> > > https://lore.kernel.org/r/f9a8c975-f5d3-4dd2-988e-4371a1433a60@hogyros.de/,
> > > right?
> >
> > And this looks like a regression in v6.18 that will persist in v6.19.
> >
> > Is that the right thing? I wonder if we should move these first five
> > patches to pci/for-linus so they land in v6.19?
>
> Fine with me if you want to do that. Stable people would pick things that
> landing in the merge window into Linus' tree anyway so the difference
> isn't going to be that huge.
>
> Patch 3 is the scariest of the changes and is not strictly even a fix
> (without it there are two parallel alignment approaches though which
> wastes some stack space). It will have some impact on resource allocation
> when the new approach is enabled for everything were as previously the new
> sizing/alignment approached were only used in the relative safe haven of
> relaxed tail alignment cases; though in my tests, surprisingly few changes
> did occur.
>
> The patch 4 too is on the edge, if you want to push that through for-linus
> (but it's not dangerous and is useful for complex topos).
>
> I don't know how you are going to handle the pci/resource branch then
> though as I expect the rest of the series to not apply cleanly without
> those 5 patches.
OK, I'll leave it as-is, with all of this on pci/resource for v6.20.
I was concerned that lots of people would trip over the issue Simon
reported, but I don't see many reports on the web.
Bjorn
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH 05/23] PCI: Remove old_size limit from bridge window sizing
2026-01-26 17:16 ` Bjorn Helgaas
2026-01-26 20:09 ` Bjorn Helgaas
@ 2026-01-27 10:16 ` Ilpo Järvinen
1 sibling, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2026-01-27 10:16 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: linux-pci, Bjorn Helgaas, Dominik Brodowski, LKML, Simon Richter
[-- Attachment #1: Type: text/plain, Size: 5469 bytes --]
On Mon, 26 Jan 2026, Bjorn Helgaas wrote:
> On Fri, Dec 19, 2025 at 07:40:18PM +0200, Ilpo Järvinen wrote:
> > calculate_memsize() applies lower bound to the resource size before
> > aligning the resource size making it impossible to shrink bridge window
> > resources. I've not found any justification for this lower bound and
> > nothing indicated it was to work around some HW issue.
> >
> > Prior to the commit 3baeae36039a ("PCI: Use pci_release_resource()
> > instead of release_resource()"), releasing a bridge window during BAR
> > resize resulted in clearing start and end address of the resource.
> > Clearing addresses destroys the resource size as a side-effect,
> > therefore nullifying the effect of the old size lower bound.
> >
> > After the commit 3baeae36039a ("PCI: Use pci_release_resource() instead
> > of release_resource()"), BAR resize uses the aligned old size, which
> > results in exceeding what fits into the parent window in some cases:
> >
> > xe 0030:03:00.0: [drm] Attempting to resize bar from 256MiB -> 16384MiB
> > xe 0030:03:00.0: BAR 0 [mem 0x620c000000000-0x620c000ffffff 64bit]: releasing
> > xe 0030:03:00.0: BAR 2 [mem 0x6200000000000-0x620000fffffff 64bit pref]: releasing
> > pci 0030:02:01.0: bridge window [mem 0x6200000000000-0x620001fffffff 64bit pref]: releasing
> > pci 0030:01:00.0: bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref]: releasing
> > pci 0030:00:00.0: bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref]: was not released (still contains assigned resources)
> > pci 0030:00:00.0: Assigned bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref] to [bus 01-04] free space at [mem 0x6200400000000-0x62007ffffffff 64bit pref]
> > pci 0030:00:00.0: Assigned bridge window [mem 0x6200000000000-0x6203fbff0ffff 64bit pref] to [bus 01-04] cannot fit 0x4000000000 required for 0030:01:00.0 bridging to [bus 02-04]
> >
> > The old size of 0x6200000000000-0x6203fbff0ffff resource was used as
> > the lower bound which results in 0x4000000000 size request due to
> > alignment. That exceed what can fit into the parent window.
> >
> > Since the lower bound never even was enforced fully because the
> > resource addresses were cleared when the bridge window is released,
> > remove the old_size lower bound entirely and trust the calculated
> > bridge window size is enough.
> >
> > This same problem may occur on io window side but seems less likely to
> > cause issues due to general difference in alignment. Removing the lower
> > bound may have other unforeseen consequences in case of io window so
> > it's better to do leave as -next material if no problem is reported
> > related to io window sizing (BAR resize shouldn't touch io windows
> > anyway).
> >
> > Reported-by: Simon Richter <Simon.Richter@hogyros.de>
>
> I guess this report was
> https://lore.kernel.org/r/f9a8c975-f5d3-4dd2-988e-4371a1433a60@hogyros.de/,
> right?
Yes,
I seem to have forgotten to add the Link once again despite trying to
really remember it. I'm sorry about that.
> > Fixes: 3baeae36039a ("PCI: Use pci_release_resource() instead of release_resource()")
> > Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
> > ---
> > drivers/pci/setup-bus.c | 11 +++--------
> > 1 file changed, 3 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
> > index 612288716ba8..8660449f59bd 100644
> > --- a/drivers/pci/setup-bus.c
> > +++ b/drivers/pci/setup-bus.c
> > @@ -1071,16 +1071,13 @@ static resource_size_t calculate_memsize(resource_size_t size,
> > resource_size_t min_size,
> > resource_size_t add_size,
> > resource_size_t children_add_size,
> > - resource_size_t old_size,
> > resource_size_t align)
> > {
> > if (size < min_size)
> > size = min_size;
> > - if (old_size == 1)
> > - old_size = 0;
> >
> > size = max(size, add_size) + children_add_size;
> > - return ALIGN(max(size, old_size), align);
> > + return ALIGN(size, align);
> > }
> >
> > resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus,
> > @@ -1298,7 +1295,6 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
> > resource_size_t children_add_size = 0;
> > resource_size_t children_add_align = 0;
> > resource_size_t add_align = 0;
> > - resource_size_t old_size;
> >
> > if (!b_res)
> > return;
> > @@ -1364,11 +1360,10 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
> > }
> > }
> >
> > - old_size = resource_size(b_res);
> > win_align = window_alignment(bus, b_res->flags);
> > min_align = calculate_head_align(aligns, max_order);
> > min_align = max(min_align, win_align);
> > - size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align);
> > + size0 = calculate_memsize(size, min_size, 0, 0, win_align);
> >
> > if (size0) {
> > resource_set_range(b_res, min_align, size0);
> > @@ -1378,7 +1373,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
> > if (realloc_head && (add_size > 0 || children_add_size > 0)) {
> > add_align = max(min_align, add_align);
> > size1 = calculate_memsize(size, min_size, add_size, children_add_size,
> > - old_size, win_align);
> > + win_align);
> > }
> >
> > if (!size0 && !size1) {
> > --
> > 2.39.5
> >
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH 06/23] PCI: Push realloc check into pbus_size_mem()
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (4 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 05/23] PCI: Remove old_size limit from bridge window sizing Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 07/23] PCI: Pass bridge window resource to pbus_size_mem() Ilpo Järvinen
` (17 subsequent siblings)
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
pbus_size_mem() and calculate_memsize() input both min_size and
add_size. They are given the same value if realloc_head is NULL and
min_size is 0 otherwise. Both are used in calculate_memsize() to
enforce a lower bound to the size.
The interface between __pci_bus_size_bridges() and the forementioned
functions can be simplied by pushing the realloc check into
pbus_size_mem().
There are only two possible cases:
1) when calculating size0, add_size parameter given to
calculate_memsize() is always 0 which implies only min_size
matters.
2) when calculating size1, realloc_head is not NULL which implies
min_size=0 so only add_size matters.
Drop min_size parameter from pbus_size_mem() and check realloc_head
when calling calculate_memsize(). Drop add_size from
calculate_memsize() and use only min_size within max() to enforce the
lower bound.
calculate_iosize() is a bit more complicated than calculate_memsize()
and is therefore left as is, but pbus_size_io() can still input only
min_size similar to pbus_size_mem().
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/pci/setup-bus.c | 34 ++++++++++++----------------------
1 file changed, 12 insertions(+), 22 deletions(-)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 8660449f59bd..f85ae20dc894 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -1069,14 +1069,10 @@ static resource_size_t calculate_iosize(resource_size_t size,
static resource_size_t calculate_memsize(resource_size_t size,
resource_size_t min_size,
- resource_size_t add_size,
resource_size_t children_add_size,
resource_size_t align)
{
- if (size < min_size)
- size = min_size;
-
- size = max(size, add_size) + children_add_size;
+ size = max(size, min_size) + children_add_size;
return ALIGN(size, align);
}
@@ -1115,8 +1111,7 @@ static resource_size_t window_alignment(struct pci_bus *bus, unsigned long type)
* pbus_size_io() - Size the I/O window of a given bus
*
* @bus: The bus
- * @min_size: The minimum I/O window that must be allocated
- * @add_size: Additional optional I/O window
+ * @add_size: Additional I/O window
* @realloc_head: Track the additional I/O window on this list
*
* Sizing the I/O windows of the PCI-PCI bridge is trivial, since these
@@ -1124,8 +1119,7 @@ static resource_size_t window_alignment(struct pci_bus *bus, unsigned long type)
* devices are limited to 256 bytes. We must be careful with the ISA
* aliasing though.
*/
-static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
- resource_size_t add_size,
+static void pbus_size_io(struct pci_bus *bus, resource_size_t add_size,
struct list_head *realloc_head)
{
struct pci_dev *dev;
@@ -1170,7 +1164,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
}
}
- size0 = calculate_iosize(size, min_size, size1, 0, 0,
+ size0 = calculate_iosize(size, realloc_head ? 0 : add_size, size1, 0, 0,
resource_size(b_res), min_align);
if (size0)
@@ -1178,7 +1172,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
size1 = size0;
if (realloc_head && (add_size > 0 || children_add_size > 0)) {
- size1 = calculate_iosize(size, min_size, size1, add_size,
+ size1 = calculate_iosize(size, 0, size1, add_size,
children_add_size, resource_size(b_res),
min_align);
}
@@ -1269,8 +1263,7 @@ static resource_size_t calculate_head_align(resource_size_t *aligns,
*
* @bus: The bus
* @type: The type of bridge resource
- * @min_size: The minimum memory window that must be allocated
- * @add_size: Additional optional memory window
+ * @add_size: Additional memory window
* @realloc_head: Track the additional memory window on this list
*
* Calculate the size of the bus resource for @type and minimal alignment
@@ -1283,7 +1276,6 @@ static resource_size_t calculate_head_align(resource_size_t *aligns,
* supplied.
*/
static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
- resource_size_t min_size,
resource_size_t add_size,
struct list_head *realloc_head)
{
@@ -1363,7 +1355,8 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
win_align = window_alignment(bus, b_res->flags);
min_align = calculate_head_align(aligns, max_order);
min_align = max(min_align, win_align);
- size0 = calculate_memsize(size, min_size, 0, 0, win_align);
+ size0 = calculate_memsize(size, realloc_head ? 0 : add_size,
+ 0, win_align);
if (size0) {
resource_set_range(b_res, min_align, size0);
@@ -1372,7 +1365,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
if (realloc_head && (add_size > 0 || children_add_size > 0)) {
add_align = max(min_align, add_align);
- size1 = calculate_memsize(size, min_size, add_size, children_add_size,
+ size1 = calculate_memsize(size, add_size, children_add_size,
win_align);
}
@@ -1550,20 +1543,17 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
}
fallthrough;
default:
- pbus_size_io(bus, realloc_head ? 0 : additional_io_size,
- additional_io_size, realloc_head);
+ pbus_size_io(bus, additional_io_size, realloc_head);
if (pref && (pref->flags & IORESOURCE_PREFETCH)) {
pbus_size_mem(bus,
IORESOURCE_MEM | IORESOURCE_PREFETCH |
(pref->flags & IORESOURCE_MEM_64),
- realloc_head ? 0 : additional_mmio_pref_size,
additional_mmio_pref_size, realloc_head);
}
- pbus_size_mem(bus, IORESOURCE_MEM,
- realloc_head ? 0 : additional_mmio_size,
- additional_mmio_size, realloc_head);
+ pbus_size_mem(bus, IORESOURCE_MEM, additional_mmio_size,
+ realloc_head);
break;
}
}
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH 07/23] PCI: Pass bridge window resource to pbus_size_mem()
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (5 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 06/23] PCI: Push realloc check into pbus_size_mem() Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 08/23] PCI: Use res_to_dev_res() in reassign_resources_sorted() Ilpo Järvinen
` (16 subsequent siblings)
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
pbus_size_mem() inputs type and calculates bridge window resource
within. Its caller (__pci_bus_size_bridges()) also has to lookup the
prefetchable window to determine if it exists or not to decide whether
to call pbus_size_mem() twice or once.
Change the interface such that the caller is responsible in providing
the bridge window resource. Passing the resource directly avoids
another lookup for the prefetchable window inside pbus_size_mem().
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/pci/setup-bus.c | 35 +++++++++++++++++------------------
1 file changed, 17 insertions(+), 18 deletions(-)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index f85ae20dc894..90bb9baf68b9 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -1262,11 +1262,11 @@ static resource_size_t calculate_head_align(resource_size_t *aligns,
* pbus_size_mem() - Size the memory window of a given bus
*
* @bus: The bus
- * @type: The type of bridge resource
+ * @b_res: The bridge window resource
* @add_size: Additional memory window
* @realloc_head: Track the additional memory window on this list
*
- * Calculate the size of the bus resource for @type and minimal alignment
+ * Calculate the size of the bridge window @b_res and minimal alignment
* which guarantees that all child resources fit in this size.
*
* Set the bus resource start/end to indicate the required size if there an
@@ -1275,15 +1275,14 @@ static resource_size_t calculate_head_align(resource_size_t *aligns,
* Add optional resource requests to the @realloc_head list if it is
* supplied.
*/
-static void pbus_size_mem(struct pci_bus *bus, unsigned long type,
- resource_size_t add_size,
- struct list_head *realloc_head)
+static void pbus_size_mem(struct pci_bus *bus, struct resource *b_res,
+ resource_size_t add_size,
+ struct list_head *realloc_head)
{
struct pci_dev *dev;
resource_size_t min_align, win_align, align, size, size0, size1 = 0;
resource_size_t aligns[28] = {}; /* Alignments from 1MB to 128TB */
int order, max_order;
- struct resource *b_res = pbus_select_window_for_type(bus, type);
resource_size_t children_add_size = 0;
resource_size_t children_add_align = 0;
resource_size_t add_align = 0;
@@ -1494,7 +1493,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
struct pci_dev *dev;
resource_size_t additional_io_size = 0, additional_mmio_size = 0,
additional_mmio_pref_size = 0;
- struct resource *pref;
+ struct resource *b_res;
struct pci_host_bridge *host;
int hdr_type;
@@ -1520,12 +1519,8 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
host = to_pci_host_bridge(bus->bridge);
if (!host->size_windows)
return;
- pci_bus_for_each_resource(bus, pref)
- if (pref && (pref->flags & IORESOURCE_PREFETCH))
- break;
hdr_type = -1; /* Intentionally invalid - not a PCI device. */
} else {
- pref = &bus->self->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
hdr_type = bus->self->hdr_type;
}
@@ -1545,15 +1540,19 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
default:
pbus_size_io(bus, additional_io_size, realloc_head);
- if (pref && (pref->flags & IORESOURCE_PREFETCH)) {
- pbus_size_mem(bus,
- IORESOURCE_MEM | IORESOURCE_PREFETCH |
- (pref->flags & IORESOURCE_MEM_64),
- additional_mmio_pref_size, realloc_head);
+ b_res = pbus_select_window_for_type(bus, IORESOURCE_MEM |
+ IORESOURCE_PREFETCH |
+ IORESOURCE_MEM_64);
+ if (b_res && (b_res->flags & IORESOURCE_PREFETCH)) {
+ pbus_size_mem(bus, b_res, additional_mmio_pref_size,
+ realloc_head);
}
- pbus_size_mem(bus, IORESOURCE_MEM, additional_mmio_size,
- realloc_head);
+ b_res = pbus_select_window_for_type(bus, IORESOURCE_MEM);
+ if (b_res) {
+ pbus_size_mem(bus, b_res, additional_mmio_size,
+ realloc_head);
+ }
break;
}
}
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH 08/23] PCI: Use res_to_dev_res() in reassign_resources_sorted()
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (6 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 07/23] PCI: Pass bridge window resource to pbus_size_mem() Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 09/23] PCI: Fetch dev_res to local var in __assign_resources_sorted() Ilpo Järvinen
` (15 subsequent siblings)
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
reassign_resources_sorted() contains a search loop for a particular
resource in the head list. res_to_dev_res() already implements the same
search so use it instead.
Drop unused found_match and dev_res variables.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/pci/setup-bus.c | 11 +----------
1 file changed, 1 insertion(+), 10 deletions(-)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 90bb9baf68b9..09cc225bf107 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -414,7 +414,6 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
struct list_head *head)
{
struct pci_dev_resource *add_res, *tmp;
- struct pci_dev_resource *dev_res;
struct pci_dev *dev;
struct resource *res;
const char *res_name;
@@ -422,8 +421,6 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
int idx;
list_for_each_entry_safe(add_res, tmp, realloc_head, list) {
- bool found_match = false;
-
res = add_res->res;
dev = add_res->dev;
idx = pci_resource_num(dev, res);
@@ -437,13 +434,7 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
goto out;
/* Skip this resource if not found in head list */
- list_for_each_entry(dev_res, head, list) {
- if (dev_res->res == res) {
- found_match = true;
- break;
- }
- }
- if (!found_match) /* Just skip */
+ if (!res_to_dev_res(head, res))
continue;
res_name = pci_resource_name(dev, idx);
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH 09/23] PCI: Fetch dev_res to local var in __assign_resources_sorted()
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (7 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 08/23] PCI: Use res_to_dev_res() in reassign_resources_sorted() Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 10/23] PCI: Add pci_resource_is_bridge_win() Ilpo Järvinen
` (14 subsequent siblings)
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
__assign_resources_sorted() calls get_res_add_size() and
get_res_add_align(), each walking through the realloc_head list to
relocate the corresponding pci_dev_resource entry.
Fetch the pci_dev_resource entry into a local variable to avoid double
walk.
In addition, reverse logic to reduce indentation level.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/pci/setup-bus.c | 33 +++++++++++++++++----------------
1 file changed, 17 insertions(+), 16 deletions(-)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 09cc225bf107..41417084ddf8 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -596,11 +596,11 @@ static void __assign_resources_sorted(struct list_head *head,
LIST_HEAD(local_fail_head);
LIST_HEAD(dummy_head);
struct pci_dev_resource *save_res;
- struct pci_dev_resource *dev_res, *tmp_res, *dev_res2;
+ struct pci_dev_resource *dev_res, *tmp_res, *dev_res2, *addsize_res;
struct resource *res;
struct pci_dev *dev;
unsigned long fail_type;
- resource_size_t add_align, align;
+ resource_size_t align;
if (!realloc_head)
realloc_head = &dummy_head;
@@ -621,8 +621,11 @@ static void __assign_resources_sorted(struct list_head *head,
list_for_each_entry_safe(dev_res, tmp_res, head, list) {
res = dev_res->res;
- res->end += get_res_add_size(realloc_head, res);
+ addsize_res = res_to_dev_res(realloc_head, res);
+ if (!addsize_res)
+ continue;
+ res->end += addsize_res->add_size;
/*
* There are two kinds of additional resources in the list:
* 1. bridge resource -- IORESOURCE_STARTALIGN
@@ -632,8 +635,8 @@ static void __assign_resources_sorted(struct list_head *head,
if (!(res->flags & IORESOURCE_STARTALIGN))
continue;
- add_align = get_res_add_align(realloc_head, res);
-
+ if (addsize_res->min_align <= res->start)
+ continue;
/*
* The "head" list is sorted by alignment so resources with
* bigger alignment will be assigned first. After we
@@ -641,17 +644,15 @@ static void __assign_resources_sorted(struct list_head *head,
* need to reorder the list by alignment to make it
* consistent.
*/
- if (add_align > res->start) {
- resource_set_range(res, add_align, resource_size(res));
-
- list_for_each_entry(dev_res2, head, list) {
- align = pci_resource_alignment(dev_res2->dev,
- dev_res2->res);
- if (add_align > align) {
- list_move_tail(&dev_res->list,
- &dev_res2->list);
- break;
- }
+ resource_set_range(res, addsize_res->min_align,
+ resource_size(res));
+
+ list_for_each_entry(dev_res2, head, list) {
+ align = pci_resource_alignment(dev_res2->dev,
+ dev_res2->res);
+ if (addsize_res->min_align > align) {
+ list_move_tail(&dev_res->list, &dev_res2->list);
+ break;
}
}
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH 10/23] PCI: Add pci_resource_is_bridge_win()
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (8 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 09/23] PCI: Fetch dev_res to local var in __assign_resources_sorted() Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 11/23] PCI: Log reset and restore of resources Ilpo Järvinen
` (13 subsequent siblings)
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
Add pci_resource_is_bridge_win() helper to simplify checking if the
resource is a bridge window.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/pci/pci-sysfs.c | 2 +-
drivers/pci/pci.h | 5 +++++
drivers/pci/setup-bus.c | 7 +++----
drivers/pci/setup-res.c | 2 +-
4 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index c2df915ad2d2..363187ba4f56 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -181,7 +181,7 @@ static ssize_t resource_show(struct device *dev, struct device_attribute *attr,
struct resource zerores = {};
/* For backwards compatibility */
- if (i >= PCI_BRIDGE_RESOURCES && i <= PCI_BRIDGE_RESOURCE_END &&
+ if (pci_resource_is_bridge_win(i) &&
res->flags & (IORESOURCE_UNSET | IORESOURCE_DISABLED))
res = &zerores;
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 0e67014aa001..c27144af550f 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -452,6 +452,11 @@ void pci_walk_bus_locked(struct pci_bus *top,
const char *pci_resource_name(struct pci_dev *dev, unsigned int i);
bool pci_resource_is_optional(const struct pci_dev *dev, int resno);
+static inline bool pci_resource_is_bridge_win(int resno)
+{
+ return resno >= PCI_BRIDGE_RESOURCES &&
+ resno <= PCI_BRIDGE_RESOURCE_END;
+}
/**
* pci_resource_num - Reverse lookup resource number from device resources
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 41417084ddf8..403139d8c86a 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -303,8 +303,7 @@ static bool pdev_resource_assignable(struct pci_dev *dev, struct resource *res)
if (!res->flags)
return false;
- if (idx >= PCI_BRIDGE_RESOURCES && idx <= PCI_BRIDGE_RESOURCE_END &&
- res->flags & IORESOURCE_DISABLED)
+ if (pci_resource_is_bridge_win(idx) && res->flags & IORESOURCE_DISABLED)
return false;
return true;
@@ -389,7 +388,7 @@ static inline void reset_resource(struct pci_dev *dev, struct resource *res)
{
int idx = pci_resource_num(dev, res);
- if (idx >= PCI_BRIDGE_RESOURCES && idx <= PCI_BRIDGE_RESOURCE_END) {
+ if (pci_resource_is_bridge_win(idx)) {
res->flags |= IORESOURCE_UNSET;
return;
}
@@ -985,7 +984,7 @@ int pci_claim_bridge_resource(struct pci_dev *bridge, int i)
{
int ret = -EINVAL;
- if (i < PCI_BRIDGE_RESOURCES || i > PCI_BRIDGE_RESOURCE_END)
+ if (!pci_resource_is_bridge_win(i))
return 0;
if (pci_claim_resource(bridge, i) == 0)
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index e5fcadfc58b0..bb2aef373d6f 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -359,7 +359,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
res->flags &= ~IORESOURCE_UNSET;
res->flags &= ~IORESOURCE_STARTALIGN;
- if (resno >= PCI_BRIDGE_RESOURCES && resno <= PCI_BRIDGE_RESOURCE_END)
+ if (pci_resource_is_bridge_win(resno))
res->flags &= ~IORESOURCE_DISABLED;
pci_info(dev, "%s %pR: assigned\n", res_name, res);
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH 11/23] PCI: Log reset and restore of resources
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (9 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 10/23] PCI: Add pci_resource_is_bridge_win() Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 12/23] PCI: Check invalid align earlier in pbus_size_mem() Ilpo Järvinen
` (12 subsequent siblings)
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
PCI resource fitting and assignment is complicated to track because it
performs many actions without any logging. One of these is resource
reset (zeroing the resource) and the restore during the multi-passed
resource fitting algorithm.
Resource reset does not play well with the other PCI code if the code
later wants to reattempt assignment of that resource, knowing that a
resource was left into the reset state without a pairing restore is
useful for understanding issues that show up as resource assignment
failures.
Add pci_dbg() to both reset and restore to be better able to track
what's going on within the resource fitting algorithm.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/pci/setup-bus.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 403139d8c86a..a5b6c555a45b 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -136,6 +136,9 @@ static resource_size_t get_res_add_align(struct list_head *head,
static void restore_dev_resource(struct pci_dev_resource *dev_res)
{
struct resource *res = dev_res->res;
+ struct pci_dev *dev = dev_res->dev;
+ int idx = pci_resource_num(dev, res);
+ const char *res_name = pci_resource_name(dev, idx);
if (WARN_ON_ONCE(res->parent))
return;
@@ -143,6 +146,8 @@ static void restore_dev_resource(struct pci_dev_resource *dev_res)
res->start = dev_res->start;
res->end = dev_res->end;
res->flags = dev_res->flags;
+
+ pci_dbg(dev, "%s %pR: resource restored\n", res_name, res);
}
/*
@@ -384,15 +389,18 @@ bool pci_resource_is_optional(const struct pci_dev *dev, int resno)
return false;
}
-static inline void reset_resource(struct pci_dev *dev, struct resource *res)
+static void reset_resource(struct pci_dev *dev, struct resource *res)
{
int idx = pci_resource_num(dev, res);
+ const char *res_name = pci_resource_name(dev, idx);
if (pci_resource_is_bridge_win(idx)) {
res->flags |= IORESOURCE_UNSET;
return;
}
+ pci_dbg(dev, "%s %pR: resetting resource\n", res_name, res);
+
res->start = 0;
res->end = 0;
res->flags = 0;
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH 12/23] PCI: Check invalid align earlier in pbus_size_mem()
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (10 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 11/23] PCI: Log reset and restore of resources Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 13/23] PCI: Add pbus_mem_size_optional() to handle optional sizes Ilpo Järvinen
` (11 subsequent siblings)
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
Check for invalid align before any bridge window sizing actions in
pbus_size_mem() to avoid need to roll back any sizing calculations.
Placing the check earlier will make it easier to add more optional size
related calculations at where the SRIOV logic currently is in
pbus_size_mem().
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/pci/setup-bus.c | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index a5b6c555a45b..3d1d3cefcdba 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -19,6 +19,7 @@
#include <linux/bug.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/errno.h>
@@ -1311,31 +1312,29 @@ static void pbus_size_mem(struct pci_bus *bus, struct resource *b_res,
continue;
r_size = resource_size(r);
-
- /* Put SRIOV requested res to the optional list */
- if (realloc_head && pci_resource_is_optional(dev, i)) {
- add_align = max(pci_resource_alignment(dev, r), add_align);
- add_to_list(realloc_head, dev, r, 0, 0 /* Don't care */);
- children_add_size += r_size;
- continue;
- }
-
+ align = pci_resource_alignment(dev, r);
/*
* aligns[0] is for 1MB (since bridge memory
* windows are always at least 1MB aligned), so
* keep "order" from being negative for smaller
* resources.
*/
- align = pci_resource_alignment(dev, r);
- order = __ffs(align) - __ffs(SZ_1M);
- if (order < 0)
- order = 0;
+ order = max_t(int, __ffs(align) - __ffs(SZ_1M), 0);
if (order >= ARRAY_SIZE(aligns)) {
pci_warn(dev, "%s %pR: disabling; bad alignment %#llx\n",
r_name, r, (unsigned long long) align);
r->flags = 0;
continue;
}
+
+ /* Put SRIOV requested res to the optional list */
+ if (realloc_head && pci_resource_is_optional(dev, i)) {
+ add_align = max(align, add_align);
+ add_to_list(realloc_head, dev, r, 0, 0 /* Don't care */);
+ children_add_size += r_size;
+ continue;
+ }
+
size += max(r_size, align);
aligns[order] += align;
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH 13/23] PCI: Add pbus_mem_size_optional() to handle optional sizes
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (11 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 12/23] PCI: Check invalid align earlier in pbus_size_mem() Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 14/23] resource: Mark res given to resource_assigned() as const Ilpo Järvinen
` (10 subsequent siblings)
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
The resource loop in pbus_size_mem() handles optional resources that
are either fully optional (SRIOV and disabled Expansion ROMs) or bridge
windows that may be optional only for a part. The logic is little
inconsistent when it comes to a bridge window that has only optional
children resources as it would be more natural to treat it similar to
any fully optional resource. As resource size should be zero in that
case, it shouldn't cause any bugs but it still seems useful to address
the inconsistency.
Place the optional size related code of pbus_size_mem() into
pbus_mem_size_optional() and add check into pci_resource_is_optional()
for entirely optional bridge windows. Reorder the logic inside
pbus_mem_size_optional() such that fully optional resources are handled
the same irrespective to whether the resource is a bridge window or
not.
Additional motivation for this are the upcoming changes that add
complexity to the optional sizing logic due to Resizable BAR awareness.
The extra logic would exceed any reasonable indentation level if the
optional sizing code is kept within the loop body.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/pci/setup-bus.c | 77 +++++++++++++++++++++++++++++------------
1 file changed, 54 insertions(+), 23 deletions(-)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 3d1d3cefcdba..3fcc7641c374 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -125,15 +125,6 @@ static resource_size_t get_res_add_size(struct list_head *head,
return dev_res ? dev_res->add_size : 0;
}
-static resource_size_t get_res_add_align(struct list_head *head,
- struct resource *res)
-{
- struct pci_dev_resource *dev_res;
-
- dev_res = res_to_dev_res(head, res);
- return dev_res ? dev_res->min_align : 0;
-}
-
static void restore_dev_resource(struct pci_dev_resource *dev_res)
{
struct resource *res = dev_res->res;
@@ -386,6 +377,8 @@ bool pci_resource_is_optional(const struct pci_dev *dev, int resno)
return true;
if (resno == PCI_ROM_RESOURCE && !(res->flags & IORESOURCE_ROM_ENABLE))
return true;
+ if (pci_resource_is_bridge_win(resno) && !resource_size(res))
+ return true;
return false;
}
@@ -1258,6 +1251,54 @@ static resource_size_t calculate_head_align(resource_size_t *aligns,
return head_align;
}
+/*
+ * pbus_size_mem_optional - Account optional resources in bridge window
+ *
+ * Account an optional resource or the optional part of the resource in bridge
+ * window size.
+ *
+ * Return: %true if the resource is entirely optional.
+ */
+static bool pbus_size_mem_optional(struct pci_dev *dev, int resno,
+ resource_size_t align,
+ struct list_head *realloc_head,
+ resource_size_t *add_align,
+ resource_size_t *children_add_size)
+{
+ struct resource *res = pci_resource_n(dev, resno);
+ bool optional = pci_resource_is_optional(dev, resno);
+ resource_size_t r_size = resource_size(res);
+ struct pci_dev_resource *dev_res;
+
+ if (!realloc_head)
+ return false;
+
+ if (!optional) {
+ /*
+ * Only bridges have optional sizes in realloc_head at this
+ * point. As res_to_dev_res() walks the entire realloc_head
+ * list, skip calling it when known unnecessary.
+ */
+ if (!pci_resource_is_bridge_win(resno))
+ return false;
+
+ dev_res = res_to_dev_res(realloc_head, res);
+ if (dev_res) {
+ *children_add_size += dev_res->add_size;
+ *add_align = max(*add_align, dev_res->min_align);
+ }
+
+ return false;
+ }
+
+ /* Put SRIOV requested res to the optional list */
+ add_to_list(realloc_head, dev, res, 0, align);
+ *children_add_size += r_size;
+ *add_align = max(align, *add_align);
+
+ return true;
+}
+
/**
* pbus_size_mem() - Size the memory window of a given bus
*
@@ -1284,7 +1325,6 @@ static void pbus_size_mem(struct pci_bus *bus, struct resource *b_res,
resource_size_t aligns[28] = {}; /* Alignments from 1MB to 128TB */
int order, max_order;
resource_size_t children_add_size = 0;
- resource_size_t children_add_align = 0;
resource_size_t add_align = 0;
if (!b_res)
@@ -1311,7 +1351,6 @@ static void pbus_size_mem(struct pci_bus *bus, struct resource *b_res,
if (b_res != pbus_select_window(bus, r))
continue;
- r_size = resource_size(r);
align = pci_resource_alignment(dev, r);
/*
* aligns[0] is for 1MB (since bridge memory
@@ -1327,25 +1366,17 @@ static void pbus_size_mem(struct pci_bus *bus, struct resource *b_res,
continue;
}
- /* Put SRIOV requested res to the optional list */
- if (realloc_head && pci_resource_is_optional(dev, i)) {
- add_align = max(align, add_align);
- add_to_list(realloc_head, dev, r, 0, 0 /* Don't care */);
- children_add_size += r_size;
+ if (pbus_size_mem_optional(dev, i, align,
+ realloc_head, &add_align,
+ &children_add_size))
continue;
- }
+ r_size = resource_size(r);
size += max(r_size, align);
aligns[order] += align;
if (order > max_order)
max_order = order;
-
- if (realloc_head) {
- children_add_size += get_res_add_size(realloc_head, r);
- children_add_align = get_res_add_align(realloc_head, r);
- add_align = max(add_align, children_add_align);
- }
}
}
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH 14/23] resource: Mark res given to resource_assigned() as const
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (12 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 13/23] PCI: Add pbus_mem_size_optional() to handle optional sizes Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:47 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 15/23] PCI: Use resource_assigned() in setup-bus.c algorithm Ilpo Järvinen
` (9 subsequent siblings)
23 siblings, 1 reply; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
The caller may hold a const struct resource which will trigger an
unnecessary warning when calling resource_assigned() as it will not
modify res in anyway.
Mark resource_assigned()'s struct resource *res parameter const to
avoid the compiler warning.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
include/linux/ioport.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 9afa30f9346f..60ca6a49839c 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -338,7 +338,7 @@ static inline bool resource_union(const struct resource *r1, const struct resour
* Check if this resource is added to a resource tree or detached. Caller is
* responsible for not racing assignment.
*/
-static inline bool resource_assigned(struct resource *res)
+static inline bool resource_assigned(const struct resource *res)
{
return res->parent;
}
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH 14/23] resource: Mark res given to resource_assigned() as const
2025-12-19 17:40 ` [PATCH 14/23] resource: Mark res given to resource_assigned() as const Ilpo Järvinen
@ 2025-12-19 17:47 ` Ilpo Järvinen
0 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:47 UTC (permalink / raw)
To: Dan Williams, Jonathan Cameron
Cc: linux-pci, Bjorn Helgaas, Dominik Brodowski, LKML
[-- Attachment #1: Type: text/plain, Size: 1182 bytes --]
On Fri, 19 Dec 2025, Ilpo Järvinen wrote:
> The caller may hold a const struct resource which will trigger an
> unnecessary warning when calling resource_assigned() as it will not
> modify res in anyway.
>
> Mark resource_assigned()'s struct resource *res parameter const to
> avoid the compiler warning.
>
> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
An afterthought right after sending, I should have Cc'ed Dan & Jonathan
to this so adding them now.
--
i.
> ---
> include/linux/ioport.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/include/linux/ioport.h b/include/linux/ioport.h
> index 9afa30f9346f..60ca6a49839c 100644
> --- a/include/linux/ioport.h
> +++ b/include/linux/ioport.h
> @@ -338,7 +338,7 @@ static inline bool resource_union(const struct resource *r1, const struct resour
> * Check if this resource is added to a resource tree or detached. Caller is
> * responsible for not racing assignment.
> */
> -static inline bool resource_assigned(struct resource *res)
> +static inline bool resource_assigned(const struct resource *res)
> {
> return res->parent;
> }
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH 15/23] PCI: Use resource_assigned() in setup-bus.c algorithm
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (13 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 14/23] resource: Mark res given to resource_assigned() as const Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 16/23] PCI: Properly prefix struct pci_dev_resource handling functions Ilpo Järvinen
` (8 subsequent siblings)
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
Many places in the resource fitting and assignment algorithm want to
know if the resource is assigned into the resource tree or not. Convert
open-coded ->parent checks to use resource_assigned().
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/pci/setup-bus.c | 64 +++++++++++++++++++++--------------------
1 file changed, 33 insertions(+), 31 deletions(-)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 3fcc7641c374..bbc615d85c88 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -132,7 +132,7 @@ static void restore_dev_resource(struct pci_dev_resource *dev_res)
int idx = pci_resource_num(dev, res);
const char *res_name = pci_resource_name(dev, idx);
- if (WARN_ON_ONCE(res->parent))
+ if (WARN_ON_ONCE(resource_assigned(res)))
return;
res->start = dev_res->start;
@@ -166,7 +166,7 @@ static struct resource *find_bus_resource_of_type(struct pci_bus *bus,
if ((r->flags & type_mask) != type)
continue;
- if (!r->parent)
+ if (!resource_assigned(r))
return r;
if (!r_assigned)
r_assigned = r;
@@ -269,7 +269,7 @@ static struct resource *pbus_select_window_for_type(struct pci_bus *bus,
struct resource *pbus_select_window(struct pci_bus *bus,
const struct resource *res)
{
- if (res->parent)
+ if (resource_assigned(res))
return res->parent;
return pbus_select_window_for_type(bus, res->flags);
@@ -308,7 +308,7 @@ static bool pdev_resource_assignable(struct pci_dev *dev, struct resource *res)
static bool pdev_resource_should_fit(struct pci_dev *dev, struct resource *res)
{
- if (res->parent)
+ if (resource_assigned(res))
return false;
if (res->flags & IORESOURCE_PCI_FIXED)
@@ -430,7 +430,7 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
* Skip resource that failed the earlier assignment and is
* not optional as it would just fail again.
*/
- if (!res->parent && resource_size(res) &&
+ if (!resource_assigned(res) && resource_size(res) &&
!pci_resource_is_optional(dev, idx))
goto out;
@@ -441,7 +441,7 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
res_name = pci_resource_name(dev, idx);
add_size = add_res->add_size;
align = add_res->min_align;
- if (!res->parent) {
+ if (!resource_assigned(res)) {
resource_set_range(res, align,
resource_size(res) + add_size);
if (pci_assign_resource(dev, idx)) {
@@ -677,7 +677,7 @@ static void __assign_resources_sorted(struct list_head *head,
list_for_each_entry(save_res, &save_head, list) {
struct resource *res = save_res->res;
- if (res->parent)
+ if (resource_assigned(res))
continue;
restore_dev_resource(save_res);
@@ -693,7 +693,8 @@ static void __assign_resources_sorted(struct list_head *head,
list_for_each_entry_safe(dev_res, tmp_res, head, list) {
res = dev_res->res;
- if (res->parent && !pci_need_to_release(fail_type, res)) {
+ if (resource_assigned(res) &&
+ !pci_need_to_release(fail_type, res)) {
/* Remove it from realloc_head list */
remove_from_list(realloc_head, res);
remove_from_list(&save_head, res);
@@ -729,7 +730,7 @@ static void __assign_resources_sorted(struct list_head *head,
res = dev_res->res;
dev = dev_res->dev;
- if (res->parent)
+ if (resource_assigned(res))
continue;
if (fail_head) {
@@ -779,7 +780,7 @@ void pci_setup_cardbus(struct pci_bus *bus)
res = bus->resource[0];
pcibios_resource_to_bus(bridge->bus, ®ion, res);
- if (res->parent && res->flags & IORESOURCE_IO) {
+ if (resource_assigned(res) && res->flags & IORESOURCE_IO) {
/*
* The IO resource is allocated a range twice as large as it
* would normally need. This allows us to set both IO regs.
@@ -793,7 +794,7 @@ void pci_setup_cardbus(struct pci_bus *bus)
res = bus->resource[1];
pcibios_resource_to_bus(bridge->bus, ®ion, res);
- if (res->parent && res->flags & IORESOURCE_IO) {
+ if (resource_assigned(res) && res->flags & IORESOURCE_IO) {
pci_info(bridge, " bridge window %pR\n", res);
pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
region.start);
@@ -803,7 +804,7 @@ void pci_setup_cardbus(struct pci_bus *bus)
res = bus->resource[2];
pcibios_resource_to_bus(bridge->bus, ®ion, res);
- if (res->parent && res->flags & IORESOURCE_MEM) {
+ if (resource_assigned(res) && res->flags & IORESOURCE_MEM) {
pci_info(bridge, " bridge window %pR\n", res);
pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
region.start);
@@ -813,7 +814,7 @@ void pci_setup_cardbus(struct pci_bus *bus)
res = bus->resource[3];
pcibios_resource_to_bus(bridge->bus, ®ion, res);
- if (res->parent && res->flags & IORESOURCE_MEM) {
+ if (resource_assigned(res) && res->flags & IORESOURCE_MEM) {
pci_info(bridge, " bridge window %pR\n", res);
pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
region.start);
@@ -854,7 +855,7 @@ static void pci_setup_bridge_io(struct pci_dev *bridge)
res = &bridge->resource[PCI_BRIDGE_IO_WINDOW];
res_name = pci_resource_name(bridge, PCI_BRIDGE_IO_WINDOW);
pcibios_resource_to_bus(bridge->bus, ®ion, res);
- if (res->parent && res->flags & IORESOURCE_IO) {
+ if (resource_assigned(res) && res->flags & IORESOURCE_IO) {
pci_read_config_word(bridge, PCI_IO_BASE, &l);
io_base_lo = (region.start >> 8) & io_mask;
io_limit_lo = (region.end >> 8) & io_mask;
@@ -886,7 +887,7 @@ static void pci_setup_bridge_mmio(struct pci_dev *bridge)
res = &bridge->resource[PCI_BRIDGE_MEM_WINDOW];
res_name = pci_resource_name(bridge, PCI_BRIDGE_MEM_WINDOW);
pcibios_resource_to_bus(bridge->bus, ®ion, res);
- if (res->parent && res->flags & IORESOURCE_MEM) {
+ if (resource_assigned(res) && res->flags & IORESOURCE_MEM) {
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
pci_info(bridge, " %s %pR\n", res_name, res);
@@ -915,7 +916,7 @@ static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge)
res = &bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
res_name = pci_resource_name(bridge, PCI_BRIDGE_PREF_MEM_WINDOW);
pcibios_resource_to_bus(bridge->bus, ®ion, res);
- if (res->parent && res->flags & IORESOURCE_PREFETCH) {
+ if (resource_assigned(res) && res->flags & IORESOURCE_PREFETCH) {
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
if (res->flags & IORESOURCE_MEM_64) {
@@ -1125,7 +1126,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t add_size,
return;
/* If resource is already assigned, nothing more to do */
- if (b_res->parent)
+ if (resource_assigned(b_res))
return;
min_align = window_alignment(bus, IORESOURCE_IO);
@@ -1135,7 +1136,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t add_size,
pci_dev_for_each_resource(dev, r) {
unsigned long r_size;
- if (r->parent || !(r->flags & IORESOURCE_IO))
+ if (resource_assigned(r) || !(r->flags & IORESOURCE_IO))
continue;
if (!pdev_resource_assignable(dev, r))
@@ -1331,7 +1332,7 @@ static void pbus_size_mem(struct pci_bus *bus, struct resource *b_res,
return;
/* If resource is already assigned, nothing more to do */
- if (b_res->parent)
+ if (resource_assigned(b_res))
return;
max_order = 0;
@@ -1436,7 +1437,7 @@ static void pci_bus_size_cardbus(struct pci_bus *bus,
u16 ctrl;
b_res = &bridge->resource[PCI_CB_BRIDGE_IO_0_WINDOW];
- if (b_res->parent)
+ if (resource_assigned(b_res))
goto handle_b_res_1;
/*
* Reserve some resources for CardBus. We reserve a fixed amount
@@ -1452,7 +1453,7 @@ static void pci_bus_size_cardbus(struct pci_bus *bus,
handle_b_res_1:
b_res = &bridge->resource[PCI_CB_BRIDGE_IO_1_WINDOW];
- if (b_res->parent)
+ if (resource_assigned(b_res))
goto handle_b_res_2;
resource_set_range(b_res, pci_cardbus_io_size, pci_cardbus_io_size);
b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
@@ -1480,7 +1481,7 @@ static void pci_bus_size_cardbus(struct pci_bus *bus,
}
b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_0_WINDOW];
- if (b_res->parent)
+ if (resource_assigned(b_res))
goto handle_b_res_3;
/*
* If we have prefetchable memory support, allocate two regions.
@@ -1503,7 +1504,7 @@ static void pci_bus_size_cardbus(struct pci_bus *bus,
handle_b_res_3:
b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_1_WINDOW];
- if (b_res->parent)
+ if (resource_assigned(b_res))
goto handle_done;
resource_set_range(b_res, pci_cardbus_mem_size, b_res_3_size);
b_res->flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN;
@@ -1619,12 +1620,13 @@ static void pdev_assign_fixed_resources(struct pci_dev *dev)
pci_dev_for_each_resource(dev, r) {
struct pci_bus *b;
- if (r->parent || !(r->flags & IORESOURCE_PCI_FIXED) ||
+ if (resource_assigned(r) ||
+ !(r->flags & IORESOURCE_PCI_FIXED) ||
!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM)))
continue;
b = dev->bus;
- while (b && !r->parent) {
+ while (b && !resource_assigned(r)) {
assign_fixed_resource_on_bus(b, r);
b = b->parent;
}
@@ -1680,7 +1682,7 @@ static void pci_claim_device_resources(struct pci_dev *dev)
for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) {
struct resource *r = &dev->resource[i];
- if (!r->flags || r->parent)
+ if (!r->flags || resource_assigned(r))
continue;
pci_claim_resource(dev, i);
@@ -1694,7 +1696,7 @@ static void pci_claim_bridge_resources(struct pci_dev *dev)
for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
struct resource *r = &dev->resource[i];
- if (!r->flags || r->parent)
+ if (!r->flags || resource_assigned(r))
continue;
pci_claim_bridge_resource(dev, i);
@@ -1777,7 +1779,7 @@ static void pci_bridge_release_resources(struct pci_bus *bus,
struct pci_dev *dev = bus->self;
int idx, ret;
- if (!b_win->parent)
+ if (!resource_assigned(b_win))
return;
idx = pci_resource_num(dev, b_win);
@@ -1973,7 +1975,7 @@ static void adjust_bridge_window(struct pci_dev *bridge, struct resource *res,
{
resource_size_t add_size, size = resource_size(res);
- if (res->parent)
+ if (resource_assigned(res))
return;
if (!new_size)
@@ -2063,7 +2065,7 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
* window.
*/
align = pci_resource_alignment(bridge, res);
- if (!res->parent && align)
+ if (!resource_assigned(res) && align)
available[i].start = min(ALIGN(available[i].start, align),
available[i].end + 1);
@@ -2512,7 +2514,7 @@ int pci_do_resource_release_and_resize(struct pci_dev *pdev, int resno, int size
i = pci_resource_num(dev, res);
- if (res->parent) {
+ if (resource_assigned(res)) {
release_child_resources(res);
pci_release_resource(dev, i);
}
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH 16/23] PCI: Properly prefix struct pci_dev_resource handling functions
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (14 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 15/23] PCI: Use resource_assigned() in setup-bus.c algorithm Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 17/23] PCI: Separate cardbus setup & build it only with CONFIG_CARDBUS Ilpo Järvinen
` (7 subsequent siblings)
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
setup-bus.c has static functions for handling struct pci_dev_resource
related operation which have no prefixes. Add prefixes to those
function names as add_to_list() will be needed in another file by an
upcoming change.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
I'm open to naming these with a different prefix, as "devres" is
already used in the other context. The current name comes from the
struct pci_dev_resource that holds information during resource fitting
and assignment algorithm (mainly old resource addresses, optional
size).
---
drivers/pci/setup-bus.c | 114 +++++++++++++++++++++-------------------
1 file changed, 61 insertions(+), 53 deletions(-)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index bbc615d85c88..3cc26fede31a 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -49,7 +49,7 @@ struct pci_dev_resource {
unsigned long flags;
};
-static void free_list(struct list_head *head)
+static void pci_dev_res_free_list(struct list_head *head)
{
struct pci_dev_resource *dev_res, *tmp;
@@ -60,16 +60,17 @@ static void free_list(struct list_head *head)
}
/**
- * add_to_list() - Add a new resource tracker to the list
+ * pci_dev_res_add_to_list() - Add a new resource tracker to the list
* @head: Head of the list
* @dev: Device to which the resource belongs
* @res: Resource to be tracked
* @add_size: Additional size to be optionally added to the resource
* @min_align: Minimum memory window alignment
*/
-static int add_to_list(struct list_head *head, struct pci_dev *dev,
- struct resource *res, resource_size_t add_size,
- resource_size_t min_align)
+static int pci_dev_res_add_to_list(struct list_head *head, struct pci_dev *dev,
+ struct resource *res,
+ resource_size_t add_size,
+ resource_size_t min_align)
{
struct pci_dev_resource *tmp;
@@ -90,7 +91,8 @@ static int add_to_list(struct list_head *head, struct pci_dev *dev,
return 0;
}
-static void remove_from_list(struct list_head *head, struct resource *res)
+static void pci_dev_res_remove_from_list(struct list_head *head,
+ struct resource *res)
{
struct pci_dev_resource *dev_res, *tmp;
@@ -125,7 +127,7 @@ static resource_size_t get_res_add_size(struct list_head *head,
return dev_res ? dev_res->add_size : 0;
}
-static void restore_dev_resource(struct pci_dev_resource *dev_res)
+static void pci_dev_res_restore(struct pci_dev_resource *dev_res)
{
struct resource *res = dev_res->res;
struct pci_dev *dev = dev_res->dev;
@@ -498,9 +500,9 @@ static void assign_requested_resources_sorted(struct list_head *head,
if (pci_assign_resource(dev, idx)) {
if (fail_head) {
- add_to_list(fail_head, dev, res,
- 0 /* don't care */,
- 0 /* don't care */);
+ pci_dev_res_add_to_list(fail_head, dev, res,
+ 0 /* don't care */,
+ 0 /* don't care */);
}
}
}
@@ -612,8 +614,9 @@ static void __assign_resources_sorted(struct list_head *head,
/* Save original start, end, flags etc at first */
list_for_each_entry(dev_res, head, list) {
- if (add_to_list(&save_head, dev_res->dev, dev_res->res, 0, 0)) {
- free_list(&save_head);
+ if (pci_dev_res_add_to_list(&save_head, dev_res->dev,
+ dev_res->res, 0, 0)) {
+ pci_dev_res_free_list(&save_head);
goto assign;
}
}
@@ -666,8 +669,9 @@ static void __assign_resources_sorted(struct list_head *head,
if (list_empty(&local_fail_head)) {
/* Remove head list from realloc_head list */
list_for_each_entry(dev_res, head, list)
- remove_from_list(realloc_head, dev_res->res);
- free_list(&save_head);
+ pci_dev_res_remove_from_list(realloc_head,
+ dev_res->res);
+ pci_dev_res_free_list(&save_head);
goto out;
}
@@ -680,10 +684,10 @@ static void __assign_resources_sorted(struct list_head *head,
if (resource_assigned(res))
continue;
- restore_dev_resource(save_res);
+ pci_dev_res_restore(save_res);
}
- free_list(&local_fail_head);
- free_list(&save_head);
+ pci_dev_res_free_list(&local_fail_head);
+ pci_dev_res_free_list(&save_head);
goto out;
}
@@ -696,26 +700,26 @@ static void __assign_resources_sorted(struct list_head *head,
if (resource_assigned(res) &&
!pci_need_to_release(fail_type, res)) {
/* Remove it from realloc_head list */
- remove_from_list(realloc_head, res);
- remove_from_list(&save_head, res);
+ pci_dev_res_remove_from_list(realloc_head, res);
+ pci_dev_res_remove_from_list(&save_head, res);
list_del(&dev_res->list);
kfree(dev_res);
}
}
- free_list(&local_fail_head);
+ pci_dev_res_free_list(&local_fail_head);
/* Release assigned resource */
list_for_each_entry(dev_res, head, list) {
res = dev_res->res;
dev = dev_res->dev;
pci_release_resource(dev, pci_resource_num(dev, res));
- restore_dev_resource(dev_res);
+ pci_dev_res_restore(dev_res);
}
/* Restore start/end/flags from saved list */
list_for_each_entry(save_res, &save_head, list)
- restore_dev_resource(save_res);
- free_list(&save_head);
+ pci_dev_res_restore(save_res);
+ pci_dev_res_free_list(&save_head);
/* Satisfy the must-have resource requests */
assign_requested_resources_sorted(head, NULL, false);
@@ -734,15 +738,15 @@ static void __assign_resources_sorted(struct list_head *head,
continue;
if (fail_head) {
- add_to_list(fail_head, dev, res,
- 0 /* don't care */,
- 0 /* don't care */);
+ pci_dev_res_add_to_list(fail_head, dev, res,
+ 0 /* don't care */,
+ 0 /* don't care */);
}
reset_resource(dev, res);
}
- free_list(head);
+ pci_dev_res_free_list(head);
}
static void pdev_assign_resources_sorted(struct pci_dev *dev,
@@ -1183,8 +1187,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t add_size,
b_res->flags |= IORESOURCE_STARTALIGN;
if (bus->self && size1 > size0 && realloc_head) {
b_res->flags &= ~IORESOURCE_DISABLED;
- add_to_list(realloc_head, bus->self, b_res, size1-size0,
- min_align);
+ pci_dev_res_add_to_list(realloc_head, bus->self, b_res,
+ size1 - size0, min_align);
pci_info(bus->self, "bridge window %pR to %pR add_size %llx\n",
b_res, &bus->busn_res,
(unsigned long long) size1 - size0);
@@ -1293,7 +1297,7 @@ static bool pbus_size_mem_optional(struct pci_dev *dev, int resno,
}
/* Put SRIOV requested res to the optional list */
- add_to_list(realloc_head, dev, res, 0, align);
+ pci_dev_res_add_to_list(realloc_head, dev, res, 0, align);
*children_add_size += r_size;
*add_align = max(align, *add_align);
@@ -1411,7 +1415,8 @@ static void pbus_size_mem(struct pci_bus *bus, struct resource *b_res,
if (bus->self && realloc_head && (size1 > size0 || add_align > min_align)) {
b_res->flags &= ~IORESOURCE_DISABLED;
add_size = size1 > size0 ? size1 - size0 : 0;
- add_to_list(realloc_head, bus->self, b_res, add_size, add_align);
+ pci_dev_res_add_to_list(realloc_head, bus->self, b_res,
+ add_size, add_align);
pci_info(bus->self, "bridge window %pR to %pR add_size %llx add_align %llx\n",
b_res, &bus->busn_res,
(unsigned long long) add_size,
@@ -1447,8 +1452,9 @@ static void pci_bus_size_cardbus(struct pci_bus *bus,
b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
if (realloc_head) {
b_res->end -= pci_cardbus_io_size;
- add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size,
- pci_cardbus_io_size);
+ pci_dev_res_add_to_list(realloc_head, bridge, b_res,
+ pci_cardbus_io_size,
+ pci_cardbus_io_size);
}
handle_b_res_1:
@@ -1459,8 +1465,9 @@ static void pci_bus_size_cardbus(struct pci_bus *bus,
b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
if (realloc_head) {
b_res->end -= pci_cardbus_io_size;
- add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size,
- pci_cardbus_io_size);
+ pci_dev_res_add_to_list(realloc_head, bridge, b_res,
+ pci_cardbus_io_size,
+ pci_cardbus_io_size);
}
handle_b_res_2:
@@ -1494,8 +1501,9 @@ static void pci_bus_size_cardbus(struct pci_bus *bus,
IORESOURCE_STARTALIGN;
if (realloc_head) {
b_res->end -= pci_cardbus_mem_size;
- add_to_list(realloc_head, bridge, b_res,
- pci_cardbus_mem_size, pci_cardbus_mem_size);
+ pci_dev_res_add_to_list(realloc_head, bridge, b_res,
+ pci_cardbus_mem_size,
+ pci_cardbus_mem_size);
}
/* Reduce that to half */
@@ -1510,8 +1518,8 @@ static void pci_bus_size_cardbus(struct pci_bus *bus,
b_res->flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN;
if (realloc_head) {
b_res->end -= b_res_3_size;
- add_to_list(realloc_head, bridge, b_res, b_res_3_size,
- pci_cardbus_mem_size);
+ pci_dev_res_add_to_list(realloc_head, bridge, b_res,
+ b_res_3_size, pci_cardbus_mem_size);
}
handle_done:
@@ -1997,7 +2005,7 @@ static void adjust_bridge_window(struct pci_dev *bridge, struct resource *res,
/* If the resource is part of the add_list, remove it now */
if (add_list)
- remove_from_list(add_list, res);
+ pci_dev_res_remove_from_list(add_list, res);
}
static void remove_dev_resource(struct resource *avail, struct pci_dev *dev,
@@ -2249,9 +2257,9 @@ static void pci_prepare_next_assign_round(struct list_head *fail_head,
/* Restore size and flags */
list_for_each_entry(fail_res, fail_head, list)
- restore_dev_resource(fail_res);
+ pci_dev_res_restore(fail_res);
- free_list(fail_head);
+ pci_dev_res_free_list(fail_head);
}
/*
@@ -2298,7 +2306,7 @@ void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus)
/* Depth last, allocate resources and update the hardware. */
__pci_bus_assign_resources(bus, add_list, &fail_head);
if (WARN_ON_ONCE(add_list && !list_empty(add_list)))
- free_list(add_list);
+ pci_dev_res_free_list(add_list);
tried_times++;
/* Any device complain? */
@@ -2313,7 +2321,7 @@ void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus)
dev_info(&bus->dev,
"Automatically enabled pci realloc, if you have problem, try booting with pci=realloc=off\n");
}
- free_list(&fail_head);
+ pci_dev_res_free_list(&fail_head);
break;
}
@@ -2361,7 +2369,7 @@ void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
__pci_bridge_assign_resources(bridge, &add_list, &fail_head);
if (WARN_ON_ONCE(!list_empty(&add_list)))
- free_list(&add_list);
+ pci_dev_res_free_list(&add_list);
tried_times++;
if (list_empty(&fail_head))
@@ -2369,7 +2377,7 @@ void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
if (tried_times >= 2) {
/* Still fail, don't need to try more */
- free_list(&fail_head);
+ pci_dev_res_free_list(&fail_head);
break;
}
@@ -2410,7 +2418,7 @@ static int pbus_reassign_bridge_resources(struct pci_bus *bus, struct resource *
/* Ignore BARs which are still in use */
if (!res->child) {
- ret = add_to_list(saved, bridge, res, 0, 0);
+ ret = pci_dev_res_add_to_list(saved, bridge, res, 0, 0);
if (ret)
return ret;
@@ -2432,12 +2440,12 @@ static int pbus_reassign_bridge_resources(struct pci_bus *bus, struct resource *
__pci_bus_size_bridges(bridge->subordinate, &added);
__pci_bridge_assign_resources(bridge, &added, &failed);
if (WARN_ON_ONCE(!list_empty(&added)))
- free_list(&added);
+ pci_dev_res_free_list(&added);
if (!list_empty(&failed)) {
if (pci_required_resource_failed(&failed, type))
ret = -ENOSPC;
- free_list(&failed);
+ pci_dev_res_free_list(&failed);
if (ret)
return ret;
@@ -2485,7 +2493,7 @@ int pci_do_resource_release_and_resize(struct pci_dev *pdev, int resno, int size
if (b_win != pbus_select_window(bus, r))
continue;
- ret = add_to_list(&saved, pdev, r, 0, 0);
+ ret = pci_dev_res_add_to_list(&saved, pdev, r, 0, 0);
if (ret)
goto restore;
pci_release_resource(pdev, i);
@@ -2503,7 +2511,7 @@ int pci_do_resource_release_and_resize(struct pci_dev *pdev, int resno, int size
out:
up_read(&pci_bus_sem);
- free_list(&saved);
+ pci_dev_res_free_list(&saved);
return ret;
restore:
@@ -2519,7 +2527,7 @@ int pci_do_resource_release_and_resize(struct pci_dev *pdev, int resno, int size
pci_release_resource(dev, i);
}
- restore_dev_resource(dev_res);
+ pci_dev_res_restore(dev_res);
ret = pci_claim_resource(dev, i);
if (ret)
@@ -2551,6 +2559,6 @@ void pci_assign_unassigned_bus_resources(struct pci_bus *bus)
up_read(&pci_bus_sem);
__pci_bus_assign_resources(bus, &add_list, NULL);
if (WARN_ON_ONCE(!list_empty(&add_list)))
- free_list(&add_list);
+ pci_dev_res_free_list(&add_list);
}
EXPORT_SYMBOL_GPL(pci_assign_unassigned_bus_resources);
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH 17/23] PCI: Separate cardbus setup & build it only with CONFIG_CARDBUS
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (15 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 16/23] PCI: Properly prefix struct pci_dev_resource handling functions Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 18/23] PCI: Handle CardBus specific params in setup-cardbus.c Ilpo Järvinen
` (6 subsequent siblings)
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
PCI bridge window setup code includes special code to handle CardBus
bridges. CardBus has long since fallen out of favor and modern systems
have no use for it.
Move CardBus setup code into own file and use existing CONFIG_CARDBUS
for deciding whether it should be built or not.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/pci/Makefile | 1 +
drivers/pci/pci.h | 23 ++++-
drivers/pci/setup-bus.c | 171 ++--------------------------------
drivers/pci/setup-cardbus.c | 167 +++++++++++++++++++++++++++++++++
drivers/pcmcia/yenta_socket.c | 2 +-
include/linux/pci.h | 6 +-
6 files changed, 202 insertions(+), 168 deletions(-)
create mode 100644 drivers/pci/setup-cardbus.c
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index e10cfe5a280b..8922f90afecb 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_PCI_TSM) += tsm.o
obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of_property.o
obj-$(CONFIG_PCI_NPEM) += npem.o
obj-$(CONFIG_PCIE_TPH) += tph.o
+obj-$(CONFIG_CARDBUS) += setup-cardbus.o
# Endpoint library must be initialized before its users
obj-$(CONFIG_PCI_ENDPOINT) += endpoint/
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index c27144af550f..2340e9df05c2 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -379,6 +379,23 @@ extern unsigned long pci_hotplug_bus_size;
extern unsigned long pci_cardbus_io_size;
extern unsigned long pci_cardbus_mem_size;
+#ifdef CONFIG_CARDBUS
+unsigned long pci_cardbus_resource_alignment(struct resource *res);
+int pci_bus_size_cardbus_bridge(struct pci_bus *bus,
+ struct list_head *realloc_head);
+
+#else
+static inline unsigned long pci_cardbus_resource_alignment(struct resource *res)
+{
+ return 0;
+}
+static inline int pci_bus_size_cardbus_bridge(struct pci_bus *bus,
+ struct list_head *realloc_head)
+{
+ return -EOPNOTSUPP;
+}
+#endif /* CONFIG_CARDBUS */
+
/**
* pci_match_one_device - Tell if a PCI device structure has a matching
* PCI device id structure
@@ -440,6 +457,10 @@ void __pci_size_stdbars(struct pci_dev *dev, int count,
int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
struct resource *res, unsigned int reg, u32 *sizes);
void pci_configure_ari(struct pci_dev *dev);
+
+int pci_dev_res_add_to_list(struct list_head *head, struct pci_dev *dev,
+ struct resource *res, resource_size_t add_size,
+ resource_size_t min_align);
void __pci_bus_size_bridges(struct pci_bus *bus,
struct list_head *realloc_head);
void __pci_bus_assign_resources(const struct pci_bus *bus,
@@ -929,8 +950,6 @@ static inline void pci_suspend_ptm(struct pci_dev *dev) { }
static inline void pci_resume_ptm(struct pci_dev *dev) { }
#endif
-unsigned long pci_cardbus_resource_alignment(struct resource *);
-
static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
struct resource *res)
{
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 3cc26fede31a..e680f75a5b5e 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -67,10 +67,9 @@ static void pci_dev_res_free_list(struct list_head *head)
* @add_size: Additional size to be optionally added to the resource
* @min_align: Minimum memory window alignment
*/
-static int pci_dev_res_add_to_list(struct list_head *head, struct pci_dev *dev,
- struct resource *res,
- resource_size_t add_size,
- resource_size_t min_align)
+int pci_dev_res_add_to_list(struct list_head *head, struct pci_dev *dev,
+ struct resource *res, resource_size_t add_size,
+ resource_size_t min_align)
{
struct pci_dev_resource *tmp;
@@ -773,61 +772,6 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus,
__assign_resources_sorted(&head, realloc_head, fail_head);
}
-void pci_setup_cardbus(struct pci_bus *bus)
-{
- struct pci_dev *bridge = bus->self;
- struct resource *res;
- struct pci_bus_region region;
-
- pci_info(bridge, "CardBus bridge to %pR\n",
- &bus->busn_res);
-
- res = bus->resource[0];
- pcibios_resource_to_bus(bridge->bus, ®ion, res);
- if (resource_assigned(res) && res->flags & IORESOURCE_IO) {
- /*
- * The IO resource is allocated a range twice as large as it
- * would normally need. This allows us to set both IO regs.
- */
- pci_info(bridge, " bridge window %pR\n", res);
- pci_write_config_dword(bridge, PCI_CB_IO_BASE_0,
- region.start);
- pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0,
- region.end);
- }
-
- res = bus->resource[1];
- pcibios_resource_to_bus(bridge->bus, ®ion, res);
- if (resource_assigned(res) && res->flags & IORESOURCE_IO) {
- pci_info(bridge, " bridge window %pR\n", res);
- pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
- region.start);
- pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1,
- region.end);
- }
-
- res = bus->resource[2];
- pcibios_resource_to_bus(bridge->bus, ®ion, res);
- if (resource_assigned(res) && res->flags & IORESOURCE_MEM) {
- pci_info(bridge, " bridge window %pR\n", res);
- pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
- region.start);
- pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0,
- region.end);
- }
-
- res = bus->resource[3];
- pcibios_resource_to_bus(bridge->bus, ®ion, res);
- if (resource_assigned(res) && res->flags & IORESOURCE_MEM) {
- pci_info(bridge, " bridge window %pR\n", res);
- pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
- region.start);
- pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1,
- region.end);
- }
-}
-EXPORT_SYMBOL(pci_setup_cardbus);
-
/*
* Initialize bridges with base/limit values we have collected. PCI-to-PCI
* Bridge Architecture Specification rev. 1.1 (1998) requires that if there
@@ -1424,108 +1368,6 @@ static void pbus_size_mem(struct pci_bus *bus, struct resource *b_res,
}
}
-unsigned long pci_cardbus_resource_alignment(struct resource *res)
-{
- if (res->flags & IORESOURCE_IO)
- return pci_cardbus_io_size;
- if (res->flags & IORESOURCE_MEM)
- return pci_cardbus_mem_size;
- return 0;
-}
-
-static void pci_bus_size_cardbus(struct pci_bus *bus,
- struct list_head *realloc_head)
-{
- struct pci_dev *bridge = bus->self;
- struct resource *b_res;
- resource_size_t b_res_3_size = pci_cardbus_mem_size * 2;
- u16 ctrl;
-
- b_res = &bridge->resource[PCI_CB_BRIDGE_IO_0_WINDOW];
- if (resource_assigned(b_res))
- goto handle_b_res_1;
- /*
- * Reserve some resources for CardBus. We reserve a fixed amount
- * of bus space for CardBus bridges.
- */
- resource_set_range(b_res, pci_cardbus_io_size, pci_cardbus_io_size);
- b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
- if (realloc_head) {
- b_res->end -= pci_cardbus_io_size;
- pci_dev_res_add_to_list(realloc_head, bridge, b_res,
- pci_cardbus_io_size,
- pci_cardbus_io_size);
- }
-
-handle_b_res_1:
- b_res = &bridge->resource[PCI_CB_BRIDGE_IO_1_WINDOW];
- if (resource_assigned(b_res))
- goto handle_b_res_2;
- resource_set_range(b_res, pci_cardbus_io_size, pci_cardbus_io_size);
- b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
- if (realloc_head) {
- b_res->end -= pci_cardbus_io_size;
- pci_dev_res_add_to_list(realloc_head, bridge, b_res,
- pci_cardbus_io_size,
- pci_cardbus_io_size);
- }
-
-handle_b_res_2:
- /* MEM1 must not be pref MMIO */
- pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
- if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM1) {
- ctrl &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1;
- pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
- pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
- }
-
- /* Check whether prefetchable memory is supported by this bridge. */
- pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
- if (!(ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0)) {
- ctrl |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM0;
- pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
- pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
- }
-
- b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_0_WINDOW];
- if (resource_assigned(b_res))
- goto handle_b_res_3;
- /*
- * If we have prefetchable memory support, allocate two regions.
- * Otherwise, allocate one region of twice the size.
- */
- if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
- resource_set_range(b_res, pci_cardbus_mem_size,
- pci_cardbus_mem_size);
- b_res->flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH |
- IORESOURCE_STARTALIGN;
- if (realloc_head) {
- b_res->end -= pci_cardbus_mem_size;
- pci_dev_res_add_to_list(realloc_head, bridge, b_res,
- pci_cardbus_mem_size,
- pci_cardbus_mem_size);
- }
-
- /* Reduce that to half */
- b_res_3_size = pci_cardbus_mem_size;
- }
-
-handle_b_res_3:
- b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_1_WINDOW];
- if (resource_assigned(b_res))
- goto handle_done;
- resource_set_range(b_res, pci_cardbus_mem_size, b_res_3_size);
- b_res->flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN;
- if (realloc_head) {
- b_res->end -= b_res_3_size;
- pci_dev_res_add_to_list(realloc_head, bridge, b_res,
- b_res_3_size, pci_cardbus_mem_size);
- }
-
-handle_done:
- ;
-}
-
void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
{
struct pci_dev *dev;
@@ -1542,7 +1384,8 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
switch (dev->hdr_type) {
case PCI_HEADER_TYPE_CARDBUS:
- pci_bus_size_cardbus(b, realloc_head);
+ if (pci_bus_size_cardbus_bridge(b, realloc_head))
+ continue;
break;
case PCI_HEADER_TYPE_BRIDGE:
@@ -1666,7 +1509,7 @@ void __pci_bus_assign_resources(const struct pci_bus *bus,
break;
case PCI_HEADER_TYPE_CARDBUS:
- pci_setup_cardbus(b);
+ pci_setup_cardbus_bridge(b);
break;
default:
@@ -1771,7 +1614,7 @@ static void __pci_bridge_assign_resources(const struct pci_dev *bridge,
break;
case PCI_CLASS_BRIDGE_CARDBUS:
- pci_setup_cardbus(b);
+ pci_setup_cardbus_bridge(b);
break;
default:
diff --git a/drivers/pci/setup-cardbus.c b/drivers/pci/setup-cardbus.c
new file mode 100644
index 000000000000..b017a2039fe1
--- /dev/null
+++ b/drivers/pci/setup-cardbus.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Cardbus bridge setup routines.
+ */
+
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+
+#include "pci.h"
+
+unsigned long pci_cardbus_resource_alignment(struct resource *res)
+{
+ if (res->flags & IORESOURCE_IO)
+ return pci_cardbus_io_size;
+ if (res->flags & IORESOURCE_MEM)
+ return pci_cardbus_mem_size;
+ return 0;
+}
+
+int pci_bus_size_cardbus_bridge(struct pci_bus *bus,
+ struct list_head *realloc_head)
+{
+ struct pci_dev *bridge = bus->self;
+ struct resource *b_res;
+ resource_size_t b_res_3_size = pci_cardbus_mem_size * 2;
+ u16 ctrl;
+
+ b_res = &bridge->resource[PCI_CB_BRIDGE_IO_0_WINDOW];
+ if (resource_assigned(b_res))
+ goto handle_b_res_1;
+ /*
+ * Reserve some resources for CardBus. We reserve a fixed amount
+ * of bus space for CardBus bridges.
+ */
+ resource_set_range(b_res, pci_cardbus_io_size, pci_cardbus_io_size);
+ b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
+ if (realloc_head) {
+ b_res->end -= pci_cardbus_io_size;
+ pci_dev_res_add_to_list(realloc_head, bridge, b_res,
+ pci_cardbus_io_size,
+ pci_cardbus_io_size);
+ }
+
+handle_b_res_1:
+ b_res = &bridge->resource[PCI_CB_BRIDGE_IO_1_WINDOW];
+ if (resource_assigned(b_res))
+ goto handle_b_res_2;
+ resource_set_range(b_res, pci_cardbus_io_size, pci_cardbus_io_size);
+ b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
+ if (realloc_head) {
+ b_res->end -= pci_cardbus_io_size;
+ pci_dev_res_add_to_list(realloc_head, bridge, b_res,
+ pci_cardbus_io_size,
+ pci_cardbus_io_size);
+ }
+
+handle_b_res_2:
+ /* MEM1 must not be pref MMIO */
+ pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
+ if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM1) {
+ ctrl &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1;
+ pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
+ pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
+ }
+
+ /* Check whether prefetchable memory is supported by this bridge. */
+ pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
+ if (!(ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0)) {
+ ctrl |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM0;
+ pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
+ pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
+ }
+
+ b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_0_WINDOW];
+ if (resource_assigned(b_res))
+ goto handle_b_res_3;
+ /*
+ * If we have prefetchable memory support, allocate two regions.
+ * Otherwise, allocate one region of twice the size.
+ */
+ if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
+ resource_set_range(b_res, pci_cardbus_mem_size,
+ pci_cardbus_mem_size);
+ b_res->flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH |
+ IORESOURCE_STARTALIGN;
+ if (realloc_head) {
+ b_res->end -= pci_cardbus_mem_size;
+ pci_dev_res_add_to_list(realloc_head, bridge, b_res,
+ pci_cardbus_mem_size,
+ pci_cardbus_mem_size);
+ }
+
+ /* Reduce that to half */
+ b_res_3_size = pci_cardbus_mem_size;
+ }
+
+handle_b_res_3:
+ b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_1_WINDOW];
+ if (resource_assigned(b_res))
+ goto handle_done;
+ resource_set_range(b_res, pci_cardbus_mem_size, b_res_3_size);
+ b_res->flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN;
+ if (realloc_head) {
+ b_res->end -= b_res_3_size;
+ pci_dev_res_add_to_list(realloc_head, bridge, b_res,
+ b_res_3_size, pci_cardbus_mem_size);
+ }
+
+handle_done:
+ return 0;
+}
+
+void pci_setup_cardbus_bridge(struct pci_bus *bus)
+{
+ struct pci_dev *bridge = bus->self;
+ struct resource *res;
+ struct pci_bus_region region;
+
+ pci_info(bridge, "CardBus bridge to %pR\n",
+ &bus->busn_res);
+
+ res = bus->resource[0];
+ pcibios_resource_to_bus(bridge->bus, ®ion, res);
+ if (resource_assigned(res) && res->flags & IORESOURCE_IO) {
+ /*
+ * The IO resource is allocated a range twice as large as it
+ * would normally need. This allows us to set both IO regs.
+ */
+ pci_info(bridge, " bridge window %pR\n", res);
+ pci_write_config_dword(bridge, PCI_CB_IO_BASE_0,
+ region.start);
+ pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0,
+ region.end);
+ }
+
+ res = bus->resource[1];
+ pcibios_resource_to_bus(bridge->bus, ®ion, res);
+ if (resource_assigned(res) && res->flags & IORESOURCE_IO) {
+ pci_info(bridge, " bridge window %pR\n", res);
+ pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
+ region.start);
+ pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1,
+ region.end);
+ }
+
+ res = bus->resource[2];
+ pcibios_resource_to_bus(bridge->bus, ®ion, res);
+ if (resource_assigned(res) && res->flags & IORESOURCE_MEM) {
+ pci_info(bridge, " bridge window %pR\n", res);
+ pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
+ region.start);
+ pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0,
+ region.end);
+ }
+
+ res = bus->resource[3];
+ pcibios_resource_to_bus(bridge->bus, ®ion, res);
+ if (resource_assigned(res) && res->flags & IORESOURCE_MEM) {
+ pci_info(bridge, " bridge window %pR\n", res);
+ pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
+ region.start);
+ pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1,
+ region.end);
+ }
+}
+EXPORT_SYMBOL(pci_setup_cardbus_bridge);
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 923ed23570a0..34c4eaee7dfc 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -779,7 +779,7 @@ static void yenta_allocate_resources(struct yenta_socket *socket)
IORESOURCE_MEM,
PCI_CB_MEMORY_BASE_1, PCI_CB_MEMORY_LIMIT_1);
if (program)
- pci_setup_cardbus(socket->dev->subordinate);
+ pci_setup_cardbus_bridge(socket->dev->subordinate);
}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 864775651c6f..ddec80c92816 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1243,7 +1243,11 @@ void pci_stop_and_remove_bus_device(struct pci_dev *dev);
void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev);
void pci_stop_root_bus(struct pci_bus *bus);
void pci_remove_root_bus(struct pci_bus *bus);
-void pci_setup_cardbus(struct pci_bus *bus);
+#ifdef CONFIG_CARDBUS
+void pci_setup_cardbus_bridge(struct pci_bus *bus);
+#else
+static inline void pci_setup_cardbus_bridge(struct pci_bus *bus) { }
+#endif
void pcibios_setup_bridge(struct pci_bus *bus, unsigned long type);
void pci_sort_breadthfirst(void);
#define dev_is_pci(d) ((d)->bus == &pci_bus_type)
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH 18/23] PCI: Handle CardBus specific params in setup-cardbus.c
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (16 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 17/23] PCI: Separate cardbus setup & build it only with CONFIG_CARDBUS Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 19/23] PCI: Use scnprintf() instead of sprintf() Ilpo Järvinen
` (5 subsequent siblings)
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
Move cardbus window sizing parameters to setup-cardbus.c that contains
all the other CardBus code.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/pci/pci.c | 14 +++-----------
drivers/pci/pci.h | 4 ++--
drivers/pci/setup-cardbus.c | 21 +++++++++++++++++++++
3 files changed, 26 insertions(+), 13 deletions(-)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 13dbb405dc31..85c22f30e20a 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -99,12 +99,6 @@ bool pci_reset_supported(struct pci_dev *dev)
int pci_domains_supported = 1;
#endif
-#define DEFAULT_CARDBUS_IO_SIZE (256)
-#define DEFAULT_CARDBUS_MEM_SIZE (64*1024*1024)
-/* pci=cbmemsize=nnM,cbiosize=nn can override this */
-unsigned long pci_cardbus_io_size = DEFAULT_CARDBUS_IO_SIZE;
-unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
-
#define DEFAULT_HOTPLUG_IO_SIZE (256)
#define DEFAULT_HOTPLUG_MMIO_SIZE (2*1024*1024)
#define DEFAULT_HOTPLUG_MMIO_PREF_SIZE (2*1024*1024)
@@ -6630,7 +6624,9 @@ static int __init pci_setup(char *str)
if (k)
*k++ = 0;
if (*str && (str = pcibios_setup(str)) && *str) {
- if (!strcmp(str, "nomsi")) {
+ if (!pci_setup_cardbus(str)) {
+ /* Function handled the parameters */
+ } else if (!strcmp(str, "nomsi")) {
pci_no_msi();
} else if (!strncmp(str, "noats", 5)) {
pr_info("PCIe: ATS is disabled\n");
@@ -6649,10 +6645,6 @@ static int __init pci_setup(char *str)
pcie_ari_disabled = true;
} else if (!strncmp(str, "notph", 5)) {
pci_no_tph();
- } else if (!strncmp(str, "cbiosize=", 9)) {
- pci_cardbus_io_size = memparse(str + 9, &str);
- } else if (!strncmp(str, "cbmemsize=", 10)) {
- pci_cardbus_mem_size = memparse(str + 10, &str);
} else if (!strncmp(str, "resource_alignment=", 19)) {
resource_alignment_param = str + 19;
} else if (!strncmp(str, "ecrc=", 5)) {
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 2340e9df05c2..dbea5db07959 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -376,13 +376,12 @@ extern unsigned long pci_hotplug_io_size;
extern unsigned long pci_hotplug_mmio_size;
extern unsigned long pci_hotplug_mmio_pref_size;
extern unsigned long pci_hotplug_bus_size;
-extern unsigned long pci_cardbus_io_size;
-extern unsigned long pci_cardbus_mem_size;
#ifdef CONFIG_CARDBUS
unsigned long pci_cardbus_resource_alignment(struct resource *res);
int pci_bus_size_cardbus_bridge(struct pci_bus *bus,
struct list_head *realloc_head);
+int pci_setup_cardbus(char *str);
#else
static inline unsigned long pci_cardbus_resource_alignment(struct resource *res)
@@ -394,6 +393,7 @@ static inline int pci_bus_size_cardbus_bridge(struct pci_bus *bus,
{
return -EOPNOTSUPP;
}
+static inline int pci_setup_cardbus(char *str) { return -ENOENT; }
#endif /* CONFIG_CARDBUS */
/**
diff --git a/drivers/pci/setup-cardbus.c b/drivers/pci/setup-cardbus.c
index b017a2039fe1..93a2b43c637b 100644
--- a/drivers/pci/setup-cardbus.c
+++ b/drivers/pci/setup-cardbus.c
@@ -3,12 +3,20 @@
* Cardbus bridge setup routines.
*/
+#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/pci.h>
+#include <linux/sizes.h>
#include <linux/types.h>
#include "pci.h"
+#define DEFAULT_CARDBUS_IO_SIZE SZ_256
+#define DEFAULT_CARDBUS_MEM_SIZE SZ_64M
+/* pci=cbmemsize=nnM,cbiosize=nn can override this */
+static unsigned long pci_cardbus_io_size = DEFAULT_CARDBUS_IO_SIZE;
+static unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
+
unsigned long pci_cardbus_resource_alignment(struct resource *res)
{
if (res->flags & IORESOURCE_IO)
@@ -165,3 +173,16 @@ void pci_setup_cardbus_bridge(struct pci_bus *bus)
}
}
EXPORT_SYMBOL(pci_setup_cardbus_bridge);
+
+int pci_setup_cardbus(char *str)
+{
+ if (!strncmp(str, "cbiosize=", 9)) {
+ pci_cardbus_io_size = memparse(str + 9, &str);
+ return 0;
+ } else if (!strncmp(str, "cbmemsize=", 10)) {
+ pci_cardbus_mem_size = memparse(str + 10, &str);
+ return 0;
+ }
+
+ return -ENOENT;
+}
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH 19/23] PCI: Use scnprintf() instead of sprintf()
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (17 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 18/23] PCI: Handle CardBus specific params in setup-cardbus.c Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 20/23] PCI: Add Bus Number + Secondary Latency Timer as dword fields Ilpo Järvinen
` (4 subsequent siblings)
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
Using sprintf() is deprecated as it does not do proper size checks.
While the code in pci_scan_bridge_extend() is safe wrt. overwriting the
destination buffer, use scnprintf() to not promote use of a deprecated
sprint() (and allow eventually removing it from the kernel).
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/pci/probe.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 41183aed8f5d..5d8ce6381dff 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -14,6 +14,7 @@
#include <linux/platform_device.h>
#include <linux/pci_hotplug.h>
#include <linux/slab.h>
+#include <linux/sprintf.h>
#include <linux/module.h>
#include <linux/cpumask.h>
#include <linux/aer.h>
@@ -1573,9 +1574,9 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
}
- sprintf(child->name,
- (is_cardbus ? "PCI CardBus %04x:%02x" : "PCI Bus %04x:%02x"),
- pci_domain_nr(bus), child->number);
+ scnprintf(child->name, sizeof(child->name),
+ (is_cardbus ? "PCI CardBus %04x:%02x" : "PCI Bus %04x:%02x"),
+ pci_domain_nr(bus), child->number);
/* Check that all devices are accessible */
while (bus->parent) {
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH 20/23] PCI: Add Bus Number + Secondary Latency Timer as dword fields
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (18 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 19/23] PCI: Use scnprintf() instead of sprintf() Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 21/23] PCI: Convert to use Bus Number field defines Ilpo Järvinen
` (3 subsequent siblings)
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
uapi/linux/pci_regs.h defines Primary/Secondary/Subordinate Bus Numbers
and Secondary Latency Timer (PCIe r7.0, sec. 7.5.1.3) as byte register
offsets but in practice the code may read/write the entire dword. In the
lack of defines to handle the dword fields, the code ends up using
literals which are not as easy to read.
Add dword field masks for the Bus Number and Secondary Latency Timer
fields.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
include/uapi/linux/pci_regs.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index 3add74ae2594..8be55ece2a21 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -132,6 +132,11 @@
#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */
#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */
#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */
+/* Masks for dword-sized processing of Bus Number and Sec Latency Timer fields */
+#define PCI_PRIMARY_BUS_MASK 0x000000ff
+#define PCI_SECONDARY_BUS_MASK 0x0000ff00
+#define PCI_SUBORDINATE_BUS_MASK 0x00ff0000
+#define PCI_SEC_LATENCY_TIMER_MASK 0xff000000
#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */
#define PCI_IO_LIMIT 0x1d
#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH 21/23] PCI: Convert to use Bus Number field defines
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (19 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 20/23] PCI: Add Bus Number + Secondary Latency Timer as dword fields Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 22/23] PCI: Add pbus_validate_busn() for Bus Number validation Ilpo Järvinen
` (2 subsequent siblings)
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
Convert literals for Primary/Secondary/Subordinate Bus Numbers
to use the field defines to improve code readability.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/pci/probe.c | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 5d8ce6381dff..1781a0a39f4a 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -526,8 +526,8 @@ static void pci_read_bridge_windows(struct pci_dev *bridge)
pci_read_config_dword(bridge, PCI_PRIMARY_BUS, &buses);
res.flags = IORESOURCE_BUS;
- res.start = (buses >> 8) & 0xff;
- res.end = (buses >> 16) & 0xff;
+ res.start = FIELD_GET(PCI_SECONDARY_BUS_MASK, buses);
+ res.end = FIELD_GET(PCI_SUBORDINATE_BUS_MASK, buses);
pci_info(bridge, "PCI bridge to %pR%s\n", &res,
bridge->transparent ? " (subtractive decode)" : "");
@@ -1395,9 +1395,9 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
pm_runtime_get_sync(&dev->dev);
pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
- primary = buses & 0xFF;
- secondary = (buses >> 8) & 0xFF;
- subordinate = (buses >> 16) & 0xFF;
+ primary = FIELD_GET(PCI_PRIMARY_BUS_MASK, buses);
+ secondary = FIELD_GET(PCI_SECONDARY_BUS_MASK, buses);
+ subordinate = FIELD_GET(PCI_SUBORDINATE_BUS_MASK, buses);
pci_dbg(dev, "scanning [bus %02x-%02x] behind bridge, pass %d\n",
secondary, subordinate, pass);
@@ -1478,7 +1478,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
* ranges.
*/
pci_write_config_dword(dev, PCI_PRIMARY_BUS,
- buses & ~0xffffff);
+ buses & PCI_SEC_LATENCY_TIMER_MASK);
goto out;
}
@@ -1509,18 +1509,19 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
if (available_buses)
available_buses--;
- buses = (buses & 0xff000000)
- | ((unsigned int)(child->primary) << 0)
- | ((unsigned int)(child->busn_res.start) << 8)
- | ((unsigned int)(child->busn_res.end) << 16);
+ buses = (buses & PCI_SEC_LATENCY_TIMER_MASK) |
+ FIELD_PREP(PCI_PRIMARY_BUS_MASK, child->primary) |
+ FIELD_PREP(PCI_SECONDARY_BUS_MASK, child->busn_res.start) |
+ FIELD_PREP(PCI_SUBORDINATE_BUS_MASK, child->busn_res.end);
/*
* yenta.c forces a secondary latency timer of 176.
* Copy that behaviour here.
*/
if (is_cardbus) {
- buses &= ~0xff000000;
- buses |= CARDBUS_LATENCY_TIMER << 24;
+ buses &= ~PCI_SEC_LATENCY_TIMER_MASK;
+ buses |= FIELD_PREP(PCI_SEC_LATENCY_TIMER_MASK,
+ CARDBUS_LATENCY_TIMER);
}
/* We need to blast all three values with a single write */
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH 22/23] PCI: Add pbus_validate_busn() for Bus Number validation
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (20 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 21/23] PCI: Convert to use Bus Number field defines Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2025-12-19 17:40 ` [PATCH 23/23] PCI: Move scanbus bridge scanning to setup-cardbus.c Ilpo Järvinen
2026-01-26 17:39 ` [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Bjorn Helgaas
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
pci_scan_bridge_extend() validates bus numbers but upcoming changes
that separate CardBus code into own function need to call that the
same validation.
Thus, add pbus_validate_busn for validating the Bus Numbers.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/pci/pci.h | 1 +
drivers/pci/probe.c | 33 +++++++++++++++++++++------------
2 files changed, 22 insertions(+), 12 deletions(-)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index dbea5db07959..b20ff7ef20ff 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -501,6 +501,7 @@ static inline int pci_resource_num(const struct pci_dev *dev,
return resno;
}
+void pbus_validate_busn(struct pci_bus *bus);
struct resource *pbus_select_window(struct pci_bus *bus,
const struct resource *res);
void pci_reassigndev_resource_alignment(struct pci_dev *dev);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 1781a0a39f4a..49468644e730 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1314,6 +1314,26 @@ static void pci_enable_rrs_sv(struct pci_dev *pdev)
static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
unsigned int available_buses);
+
+void pbus_validate_busn(struct pci_bus *bus)
+{
+ struct pci_bus *upstream = bus->parent;
+ struct pci_dev *bridge = bus->self;
+
+ /* Check that all devices are accessible */
+ while (upstream->parent) {
+ if ((bus->busn_res.end > upstream->busn_res.end) ||
+ (bus->number > upstream->busn_res.end) ||
+ (bus->number < upstream->number) ||
+ (bus->busn_res.end < upstream->number)) {
+ pci_info(bridge, "devices behind bridge are unusable because %pR cannot be assigned for them\n",
+ &bus->busn_res);
+ break;
+ }
+ upstream = upstream->parent;
+ }
+}
+
/**
* pci_ea_fixed_busnrs() - Read fixed Secondary and Subordinate bus
* numbers from EA capability.
@@ -1579,18 +1599,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
(is_cardbus ? "PCI CardBus %04x:%02x" : "PCI Bus %04x:%02x"),
pci_domain_nr(bus), child->number);
- /* Check that all devices are accessible */
- while (bus->parent) {
- if ((child->busn_res.end > bus->busn_res.end) ||
- (child->number > bus->busn_res.end) ||
- (child->number < bus->number) ||
- (child->busn_res.end < bus->number)) {
- dev_info(&dev->dev, "devices behind bridge are unusable because %pR cannot be assigned for them\n",
- &child->busn_res);
- break;
- }
- bus = bus->parent;
- }
+ pbus_validate_busn(child);
out:
/* Clear errors in the Secondary Status Register */
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH 23/23] PCI: Move scanbus bridge scanning to setup-cardbus.c
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (21 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 22/23] PCI: Add pbus_validate_busn() for Bus Number validation Ilpo Järvinen
@ 2025-12-19 17:40 ` Ilpo Järvinen
2026-01-26 17:39 ` [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Bjorn Helgaas
23 siblings, 0 replies; 36+ messages in thread
From: Ilpo Järvinen @ 2025-12-19 17:40 UTC (permalink / raw)
To: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
Cc: Ilpo Järvinen
PCI core's pci_scan_bridge_extend() contains convoluted logic specific
to setting up bus numbers for legacy CardBus bridges. Extract the
CardBus specific part out into setup-cardbus.c to make the core code
cleaner and allow leaving CardBus bridge support out from modern
systems.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
I'm somewhat skeptical that EA capability is relevant for CardBus
bridge but I've left it in place as I'm not 100% sure about it. ECN for
EA Capability is from 2014 which is quite late considering CardBus
timeline (PCMCIA ceased to exist in 2009). If it's not relevant,
dropping its support from CardBus side would allow small
simplifications to pci_cardbus_scan_bridge_extend().
---
drivers/pci/pci.h | 16 +++++
drivers/pci/probe.c | 73 +++++-----------------
drivers/pci/setup-cardbus.c | 118 ++++++++++++++++++++++++++++++++++++
3 files changed, 149 insertions(+), 58 deletions(-)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index b20ff7ef20ff..c586bf8a9da9 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -242,6 +242,7 @@ void pci_config_pm_runtime_put(struct pci_dev *dev);
void pci_pm_power_up_and_verify_state(struct pci_dev *pci_dev);
void pci_pm_init(struct pci_dev *dev);
void pci_ea_init(struct pci_dev *dev);
+bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub);
void pci_msi_init(struct pci_dev *dev);
void pci_msix_init(struct pci_dev *dev);
bool pci_bridge_d3_possible(struct pci_dev *dev);
@@ -377,10 +378,17 @@ extern unsigned long pci_hotplug_mmio_size;
extern unsigned long pci_hotplug_mmio_pref_size;
extern unsigned long pci_hotplug_bus_size;
+static inline bool pci_is_cardbus_bridge(struct pci_dev *dev)
+{
+ return dev->hdr_type == PCI_HEADER_TYPE_CARDBUS;
+}
#ifdef CONFIG_CARDBUS
unsigned long pci_cardbus_resource_alignment(struct resource *res);
int pci_bus_size_cardbus_bridge(struct pci_bus *bus,
struct list_head *realloc_head);
+int pci_cardbus_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
+ u32 buses, int max,
+ unsigned int available_buses, int pass);
int pci_setup_cardbus(char *str);
#else
@@ -393,6 +401,14 @@ static inline int pci_bus_size_cardbus_bridge(struct pci_bus *bus,
{
return -EOPNOTSUPP;
}
+static inline int pci_cardbus_scan_bridge_extend(struct pci_bus *bus,
+ struct pci_dev *dev,
+ u32 buses, int max,
+ unsigned int available_buses,
+ int pass)
+{
+ return max;
+}
static inline int pci_setup_cardbus(char *str) { return -ENOENT; }
#endif /* CONFIG_CARDBUS */
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 49468644e730..89f0717efd48 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -25,9 +25,6 @@
#include <linux/bitfield.h>
#include "pci.h"
-#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
-#define CARDBUS_RESERVE_BUSNR 3
-
static struct resource busn_resource = {
.name = "PCI busn",
.start = 0,
@@ -1345,7 +1342,7 @@ void pbus_validate_busn(struct pci_bus *bus)
* and subordinate bus numbers, return true with the bus numbers in @sec
* and @sub. Otherwise return false.
*/
-static bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub)
+bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub)
{
int ea, offset;
u32 dw;
@@ -1399,8 +1396,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
int pass)
{
struct pci_bus *child;
- int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
- u32 buses, i, j = 0;
+ u32 buses;
u16 bctl;
u8 primary, secondary, subordinate;
int broken = 0;
@@ -1444,8 +1440,15 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
pci_write_config_word(dev, PCI_BRIDGE_CONTROL,
bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT);
- if ((secondary || subordinate) && !pcibios_assign_all_busses() &&
- !is_cardbus && !broken) {
+ if (pci_is_cardbus_bridge(dev)) {
+ max = pci_cardbus_scan_bridge_extend(bus, dev, buses, max,
+ available_buses,
+ pass);
+ goto out;
+ }
+
+ if ((secondary || subordinate) &&
+ !pcibios_assign_all_busses() && !broken) {
unsigned int cmax, buses;
/*
@@ -1487,7 +1490,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
* do in the second pass.
*/
if (!pass) {
- if (pcibios_assign_all_busses() || broken || is_cardbus)
+ if (pcibios_assign_all_busses() || broken)
/*
* Temporarily disable forwarding of the
@@ -1534,55 +1537,11 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
FIELD_PREP(PCI_SECONDARY_BUS_MASK, child->busn_res.start) |
FIELD_PREP(PCI_SUBORDINATE_BUS_MASK, child->busn_res.end);
- /*
- * yenta.c forces a secondary latency timer of 176.
- * Copy that behaviour here.
- */
- if (is_cardbus) {
- buses &= ~PCI_SEC_LATENCY_TIMER_MASK;
- buses |= FIELD_PREP(PCI_SEC_LATENCY_TIMER_MASK,
- CARDBUS_LATENCY_TIMER);
- }
-
/* We need to blast all three values with a single write */
pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
- if (!is_cardbus) {
- child->bridge_ctl = bctl;
- max = pci_scan_child_bus_extend(child, available_buses);
- } else {
-
- /*
- * For CardBus bridges, we leave 4 bus numbers as
- * cards with a PCI-to-PCI bridge can be inserted
- * later.
- */
- for (i = 0; i < CARDBUS_RESERVE_BUSNR; i++) {
- struct pci_bus *parent = bus;
- if (pci_find_bus(pci_domain_nr(bus),
- max+i+1))
- break;
- while (parent->parent) {
- if ((!pcibios_assign_all_busses()) &&
- (parent->busn_res.end > max) &&
- (parent->busn_res.end <= max+i)) {
- j = 1;
- }
- parent = parent->parent;
- }
- if (j) {
-
- /*
- * Often, there are two CardBus
- * bridges -- try to leave one
- * valid bus number for each one.
- */
- i /= 2;
- break;
- }
- }
- max += i;
- }
+ child->bridge_ctl = bctl;
+ max = pci_scan_child_bus_extend(child, available_buses);
/*
* Set subordinate bus number to its real value.
@@ -1594,9 +1553,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
pci_bus_update_busn_res_end(child, max);
pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
}
-
- scnprintf(child->name, sizeof(child->name),
- (is_cardbus ? "PCI CardBus %04x:%02x" : "PCI Bus %04x:%02x"),
+ scnprintf(child->name, sizeof(child->name), "PCI Bus %04x:%02x",
pci_domain_nr(bus), child->number);
pbus_validate_busn(child);
diff --git a/drivers/pci/setup-cardbus.c b/drivers/pci/setup-cardbus.c
index 93a2b43c637b..1ebd13a1f730 100644
--- a/drivers/pci/setup-cardbus.c
+++ b/drivers/pci/setup-cardbus.c
@@ -3,14 +3,19 @@
* Cardbus bridge setup routines.
*/
+#include <linux/bitfield.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/sizes.h>
+#include <linux/sprintf.h>
#include <linux/types.h>
#include "pci.h"
+#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
+#define CARDBUS_RESERVE_BUSNR 3
+
#define DEFAULT_CARDBUS_IO_SIZE SZ_256
#define DEFAULT_CARDBUS_MEM_SIZE SZ_64M
/* pci=cbmemsize=nnM,cbiosize=nn can override this */
@@ -186,3 +191,116 @@ int pci_setup_cardbus(char *str)
return -ENOENT;
}
+
+int pci_cardbus_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
+ u32 buses, int max,
+ unsigned int available_buses, int pass)
+{
+ struct pci_bus *child;
+ bool fixed_buses;
+ u8 fixed_sec, fixed_sub;
+ int next_busnr;
+ u32 i, j = 0;
+
+ /*
+ * We need to assign a number to this bus which we always do in the
+ * second pass.
+ */
+ if (!pass) {
+ /*
+ * Temporarily disable forwarding of the configuration
+ * cycles on all bridges in this bus segment to avoid
+ * possible conflicts in the second pass between two bridges
+ * programmed with overlapping bus ranges.
+ */
+ pci_write_config_dword(dev, PCI_PRIMARY_BUS,
+ buses & PCI_SEC_LATENCY_TIMER_MASK);
+ return max;
+ }
+
+ /* Clear errors */
+ pci_write_config_word(dev, PCI_STATUS, 0xffff);
+
+ /* Read bus numbers from EA Capability (if present) */
+ fixed_buses = pci_ea_fixed_busnrs(dev, &fixed_sec, &fixed_sub);
+ if (fixed_buses)
+ next_busnr = fixed_sec;
+ else
+ next_busnr = max + 1;
+
+ /*
+ * Prevent assigning a bus number that already exists. This can
+ * happen when a bridge is hot-plugged, so in this case we only
+ * re-scan this bus.
+ */
+ child = pci_find_bus(pci_domain_nr(bus), next_busnr);
+ if (!child) {
+ child = pci_add_new_bus(bus, dev, next_busnr);
+ if (!child)
+ return max;
+ pci_bus_insert_busn_res(child, next_busnr, bus->busn_res.end);
+ }
+ max++;
+ if (available_buses)
+ available_buses--;
+
+ buses = (buses & PCI_SEC_LATENCY_TIMER_MASK) |
+ FIELD_PREP(PCI_PRIMARY_BUS_MASK, child->primary) |
+ FIELD_PREP(PCI_SECONDARY_BUS_MASK, child->busn_res.start) |
+ FIELD_PREP(PCI_SUBORDINATE_BUS_MASK, child->busn_res.end);
+
+ /*
+ * yenta.c forces a secondary latency timer of 176.
+ * Copy that behaviour here.
+ */
+ buses &= ~PCI_SEC_LATENCY_TIMER_MASK;
+ buses |= FIELD_PREP(PCI_SEC_LATENCY_TIMER_MASK, CARDBUS_LATENCY_TIMER);
+
+ /* We need to blast all three values with a single write */
+ pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
+
+ /*
+ * For CardBus bridges, we leave 4 bus numbers as cards with a
+ * PCI-to-PCI bridge can be inserted later.
+ */
+ for (i = 0; i < CARDBUS_RESERVE_BUSNR; i++) {
+ struct pci_bus *parent = bus;
+
+ if (pci_find_bus(pci_domain_nr(bus), max + i + 1))
+ break;
+
+ while (parent->parent) {
+ if (!pcibios_assign_all_busses() &&
+ (parent->busn_res.end > max) &&
+ (parent->busn_res.end <= max + i)) {
+ j = 1;
+ }
+ parent = parent->parent;
+ }
+ if (j) {
+ /*
+ * Often, there are two CardBus bridges -- try to
+ * leave one valid bus number for each one.
+ */
+ i /= 2;
+ break;
+ }
+ }
+ max += i;
+
+ /*
+ * Set subordinate bus number to its real value. If fixed
+ * subordinate bus number exists from EA capability then use it.
+ */
+ if (fixed_buses)
+ max = fixed_sub;
+ pci_bus_update_busn_res_end(child, max);
+ pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
+
+ scnprintf(child->name, sizeof(child->name), "PCI CardBus %04x:%02x",
+ pci_domain_nr(bus), child->number);
+
+ pbus_validate_busn(child);
+
+ return max;
+}
--
2.39.5
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups
2025-12-19 17:40 [PATCH 00/23] PCI: Resource code fixes (supercedes earlier series) & cleanups Ilpo Järvinen
` (22 preceding siblings ...)
2025-12-19 17:40 ` [PATCH 23/23] PCI: Move scanbus bridge scanning to setup-cardbus.c Ilpo Järvinen
@ 2026-01-26 17:39 ` Bjorn Helgaas
23 siblings, 0 replies; 36+ messages in thread
From: Bjorn Helgaas @ 2026-01-26 17:39 UTC (permalink / raw)
To: Ilpo Järvinen
Cc: linux-pci, Bjorn Helgaas, Dominik Brodowski, linux-kernel
On Fri, Dec 19, 2025 at 07:40:13PM +0200, Ilpo Järvinen wrote:
> Hi all,
>
> Here's the resource code fixes and cleanups series. The 6 patches (the
> first 5 + 1 cleanup) have been submitted earlier (not yet applied, I've
> closed the patchwork entries for them) but due to a number conflicts
> that could easily ensue if these are applied independently, I had to
> put all these into the same series.
>
> The series consists of:
>
> 1. The first 5 are the most important changes as they relate to
> regressions. These may case shrinkage of bridge windows that
> previous had surplus space beyond the HP reservation size (due to
> sizes inherited from FW). In some HP scenarios the smaller bridge
> window could cause a regression, but this seems a case the pci=hpmm*
> parameters are meant to address.
>
> 2. Followed by cleanups (no functional change intended, excluding the
> extra debug logging added).
>
> 3. Introduction of pbus_mem_size_optional() to avoid the need to handle
> optional resource in a deeply nested loop (rebar awareness changes
> will have to add some code there). Doing all optional calculations
> in one place feels more logical and consistent anyway. There's a
> minor functional change in this change related to bridge windows
> with only optional resources (I don't expect issues because of it).
>
> 4. Separating CardBus bridge setup code to own file + compile it only
> when CONFIG_CARDBUS is set (I'd have wanted to send this separately
> but it seems impractical given that I need to rename the
> pci_dev_resource handling functions when exposing them to another
> file).
>
> Any comments are welcome.
>
>
> Ilpo Järvinen (23):
> PCI: Fix bridge window alignment with optional resources
> PCI: Rewrite bridge window head alignment function
> PCI: Stop over-estimating bridge window size
> resource: Increase MAX_IORES_LEVEL to 8
> PCI: Remove old_size limit from bridge window sizing
> PCI: Push realloc check into pbus_size_mem()
> PCI: Pass bridge window resource to pbus_size_mem()
> PCI: Use res_to_dev_res() in reassign_resources_sorted()
> PCI: Fetch dev_res to local var in __assign_resources_sorted()
> PCI: Add pci_resource_is_bridge_win()
> PCI: Log reset and restore of resources
> PCI: Check invalid align earlier in pbus_size_mem()
> PCI: Add pbus_mem_size_optional() to handle optional sizes
> resource: Mark res given to resource_assigned() as const
> PCI: Use resource_assigned() in setup-bus.c algorithm
> PCI: Properly prefix struct pci_dev_resource handling functions
> PCI: Separate cardbus setup & build it only with CONFIG_CARDBUS
> PCI: Handle CardBus specific params in setup-cardbus.c
> PCI: Use scnprintf() instead of sprintf()
> PCI: Add Bus Number + Secondary Latency Timer as dword fields
> PCI: Convert to use Bus Number field defines
> PCI: Add pbus_validate_busn() for Bus Number validation
> PCI: Move scanbus bridge scanning to setup-cardbus.c
>
> drivers/pci/Makefile | 1 +
> drivers/pci/pci-sysfs.c | 2 +-
> drivers/pci/pci.c | 14 +-
> drivers/pci/pci.h | 49 ++-
> drivers/pci/probe.c | 128 +++----
> drivers/pci/setup-bus.c | 644 ++++++++++++----------------------
> drivers/pci/setup-cardbus.c | 306 ++++++++++++++++
> drivers/pci/setup-res.c | 2 +-
> drivers/pcmcia/yenta_socket.c | 2 +-
> include/linux/ioport.h | 2 +-
> include/linux/pci.h | 6 +-
> include/uapi/linux/pci_regs.h | 5 +
> kernel/resource.c | 2 +-
> 13 files changed, 648 insertions(+), 515 deletions(-)
> create mode 100644 drivers/pci/setup-cardbus.c
Sorry I missed this earlier. I put these on pci/resource, hoping we
can still make it for v6.20 since we have an extra week in the cycle
(two weeks left until v6.19 final).
^ permalink raw reply [flat|nested] 36+ messages in thread