Linux PCI subsystem development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
	linux-pci@vger.kernel.org
Subject: Re: [PATCH v4 4/7] PCI: Fix nesting windows with remainder at the left edge
Date: Wed, 21 Oct 2026 13:32:29 +0000	[thread overview]
Message-ID: <sashiko-outbox-180311@kernel.org> (raw)
In-Reply-To: <20261021124956.4250-5-ilpo.jarvinen@linux.intel.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] PCI: pci_resreq_remainder() treats size < align as tail remainder
- [Medium] PCI: wrong bus passed to pci_min_window_alignment() in __pci_assign_resource()
--

commit d393d2dd34eb6d31504106da364759753902d029
Author: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>

PCI: Fix nesting windows with remainder at the left edge

This commit wraps pcibios_align_resource() with pci_resreq_check() and passes
a smaller alignment constraint to the resource allocator when a memory
resource has a non-zero remainder. This allows nested bridge windows with a
remainder at the left edge to fit into parent windows of the same size while
preserving the real alignment in pci_resreq_data.

> diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
> index 441a62807719d..2ca3784aa323f 100644
> --- a/drivers/pci/setup-res.c
> +++ b/drivers/pci/setup-res.c

[ ... ]

> @@ -260,6 +262,12 @@ resource_size_t pci_resource_alignment(const struct pci_dev *dev,
>  	return resource_alignment(res);
>  }
>  
> +static resource_size_t pci_resreq_remainder(resource_size_t size,
> +					    resource_size_t align)
> +{
> +	return size - ALIGN_DOWN(size, align);
> +}
> +
>  /*
>   * For mem bridge windows, try to relocate tail remainder space to space
>   * before res->start if there's enough free space there. This enables
> @@ -280,10 +288,17 @@ resource_size_t pci_align_resource(struct pci_resreq_data *rr,
>  	if (rr->user_align)
>  		return res->start;
>  
> -	if (IS_ALIGNED(size, align))
> +	remainder = pci_resreq_remainder(size, align);
> +	if (!remainder)
> +		return res->start;
> +
> +	/*
> +	 * Size constraints forced an early start move in
> +	 * pci_check_and_align_resource()?
> +	 */
> +	if (!IS_ALIGNED(res->start, align))
>  		return res->start;
>  
> -	remainder = size - ALIGN_DOWN(size, align);
>  	/* Don't mess with size that doesn't align with window size granularity */
>  	if (!IS_ALIGNED(remainder, pci_min_window_alignment(dev->bus, res->flags)))
>  		return res->start;
> @@ -315,6 +330,33 @@ resource_size_t __weak pcibios_align_resource(void *data,
>  	return pci_align_resource(rr, res, empty_res, size, align);
>  }
>  
> +static resource_size_t pci_resreq_check(void *data,
> +					const struct resource *res,
> +					const struct resource *empty_res,
> +					resource_size_t size,
> +					resource_size_t min_align)
> +{
> +	struct pci_resreq_data *rr = data;
> +	resource_size_t align = rr->real_align;
> +	resource_size_t remainder, start;
> +	struct resource tmp = *res;
> +
> +	if (res->flags & IORESOURCE_MEM && !IS_ALIGNED(res->start, align)) {
> +		resource_set_range(&tmp, ALIGN(res->start, align), size);
> +		if (!__resource_contains_unbound(empty_res, &tmp)) {
> +			remainder = pci_resreq_remainder(size, align);
> +			resource_set_range(&tmp, tmp.start - remainder, size);
> +			if (!__resource_contains_unbound(empty_res, &tmp))
> +				return tmp.start;	/* caller skips range */
> +		}
> +	}

[Severity: High]
What happens in pci_resreq_remainder() and pci_resreq_check() when a memory
resource has size < align and rr.user_align is 0?

When size < align, ALIGN_DOWN(size, align) evaluates to 0, so
pci_resreq_remainder(size, align) returns size instead of 0. That treats the
entire resource as a movable remainder even though it has no align-sized
portion.

This can occur with rr.user_align == 0 in paths such as:

1. On PowerNV, pcibios_default_alignment() -> pnv_pci_default_alignment()
   returns PAGE_SIZE (for example, 64 KiB). When no pci=resource_alignment=
   parameter matches the device, pci_reassigndev_resource_alignment() ->
   pci_specified_resource_alignment(dev, &resize) returns align = PAGE_SIZE
   with resize = false. For a 4 KiB BAR, pci_request_resource_alignment()
   sets IORESOURCE_STARTALIGN with r->start = PAGE_SIZE while keeping
   size = 4 KiB, and pci_init_pci_resreq_data() leaves rr.user_align = 0.

2. For a CardBus bridge (PCI_CLASS_BRIDGE_CARDBUS), BAR 0 has size = 4 KiB
   while pci_resource_alignment() -> pci_cardbus_resource_alignment()
   returns 64 MiB with rr.user_align == 0.

In __pci_assign_resource(), because pci_resreq_remainder(size, align) is
non-zero and !pci_resource_is_bridge_win(resno), the alignment constraint
passed to pci_bus_alloc_resource() is lowered to 1U.

Then in pci_resreq_check(), if an unaligned free range empty_res cannot fit
[ALIGN(res->start, align), ALIGN(res->start, align) + size - 1], subtracting
remainder (which equals size) shifts tmp.start to
ALIGN(res->start, align) - size. If that range fits within empty_res, the
resource is assigned just below the alignment boundary at an unaligned
address (for example, 0x8000f000 in [0x80001000, 0x8000ffff] after an earlier
4 KiB BAR at 0x80000000), violating the required alignment.

Later in the series, commit "PCI: Place resources to either edge of the
window" also uses pci_resreq_remainder() in pci_align_resource() to construct
candidates at ALIGN(empty_res->start, align) - remainder and
ALIGN_DOWN(empty_res->end + 1, align) - size, which similarly selects
unaligned addresses when size < align.

Should pci_resreq_remainder() return 0 when size < align?

> +
> +	start = pcibios_align_resource(rr, &tmp, empty_res, size, align);
> +	WARN_ON_ONCE(!IS_ALIGNED(start, min_align));
> +
> +	return start;
> +}
> +
>  static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
>  		int resno, resource_size_t size, resource_size_t align)
>  {
> @@ -324,9 +366,17 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
>  	int ret;
>  
>  	pci_init_pci_resreq_data(&rr, dev);
> +	rr.real_align = align;
>  
>  	min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
>  
> +	if (!rr.user_align &&
> +	    (res->flags & IORESOURCE_MEM) && pci_resreq_remainder(size, align)) {
> +		align = 1U;
> +		if (pci_resource_is_bridge_win(resno))
> +			align = pci_min_window_alignment(bus, res->flags);
> +	}

[Severity: Medium]
Should pci_min_window_alignment() here (and in pci_align_resource()) be
passed dev->subordinate instead of bus?

When sizing bridge windows in pbus_size_io() and pbus_size_mem(),
pci_min_window_alignment() is called with the bridge's subordinate bus
(where bus->self is the bridge device dev):

drivers/pci/setup-bus.c:pbus_size_mem() {
	...
	win_align = pci_min_window_alignment(bus, b_res->flags);
}

On PowerNV, pnv_pci_window_alignment() walks up from bridge = bus->self
counting PCI_EXP_TYPE_PCI_BRIDGE devices:

arch/powerpc/platforms/powernv/pci-ioda.c:pnv_pci_window_alignment() {
	...
	bridge = bus->self;
	while (bridge) {
		if (pci_pcie_type(bridge) == PCI_EXP_TYPE_PCI_BRIDGE) {
			num_pci_bridges++;
			if (num_pci_bridges >= 2)
				return 1;
		}

		bridge = bridge->bus->self;
	}
	...
}

In __pci_assign_resource(), dev is the bridge whose window res is being
assigned, while bus is dev->bus (or an ancestor bus). For a second-level
PCI_EXP_TYPE_PCI_BRIDGE bridge on PowerNV, pbus_size_mem(dev->subordinate,
...) sizes the window with a 1 MiB minimum window alignment
(num_pci_bridges >= 2), whereas calling pci_min_window_alignment(bus,
res->flags) with dev->bus sees num_pci_bridges == 1 and returns m32_segsize
or m64_segsize (for example, 16 MiB or 64 MiB) as min_align.

If pci_resreq_check() (or pci_align_resource() in the subsequent commit
"PCI: Place resources to either edge of the window") places the window at an
address shifted by remainder that is aligned to dev->subordinate's 1 MiB
window alignment but not to the parent bus's segment size, can that reject
valid candidates or trigger WARN_ON_ONCE(!IS_ALIGNED(start, min_align)) in
pci_resreq_check()?

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261021124956.4250-1-ilpo.jarvinen@linux.intel.com?part=4

  reply	other threads:[~2026-10-21 13:32 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-21 12:49 [PATCH v4 0/7] PCI: Resource placement algorithm fixe Ilpo Järvinen
2026-10-21 12:49 ` [PATCH v4 1/7] resource: Mark free space assigned Ilpo Järvinen
2026-10-21 12:56   ` sashiko-bot
2026-10-21 12:49 ` [PATCH v4 2/7] PCI/parisc: Clean up resource debug print & use dynamic debug Ilpo Järvinen
2026-10-21 12:56   ` sashiko-bot
2026-10-21 12:49 ` [PATCH v4 3/7] PCI: Honor alignment overrides Ilpo Järvinen
2026-10-21 13:22   ` sashiko-bot
2026-10-21 12:49 ` [PATCH v4 4/7] PCI: Fix nesting windows with remainder at the left edge Ilpo Järvinen
2026-10-21 13:32   ` sashiko-bot [this message]
2026-10-21 12:49 ` [PATCH v4 5/7] linux/log2.h: Add 64-bit roundup/down_pow_of_two64() variants Ilpo Järvinen
2026-10-21 12:57   ` sashiko-bot
2026-10-21 12:49 ` [PATCH v4 6/7] PCI: Place resources to either edge of the window Ilpo Järvinen
2026-10-21 13:30   ` sashiko-bot
2026-10-21 12:49 ` [PATCH v4 7/7] PCI: Fix composite resource sizing Ilpo Järvinen
2026-10-21 13:25   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-180311@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=ilpo.jarvinen@linux.intel.com \
    --cc=linux-pci@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox