From: "Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>
To: "Ville Syrjälä" <ville.syrjala@linux.intel.com>
Cc: "Alex Bennée" <alex.bennee@linaro.org>,
"Simon Richter" <Simon.Richter@hogyros.de>,
"Lucas De Marchi" <lucas.demarchi@intel.com>,
"Alex Deucher" <alexander.deucher@amd.com>,
amd-gfx@lists.freedesktop.org,
"Bjorn Helgaas" <bhelgaas@google.com>,
"David Airlie" <airlied@gmail.com>,
dri-devel@lists.freedesktop.org, intel-gfx@lists.freedesktop.org,
intel-xe@lists.freedesktop.org,
"Jani Nikula" <jani.nikula@linux.intel.com>,
"Joonas Lahtinen" <joonas.lahtinen@linux.intel.com>,
linux-pci@vger.kernel.org,
"Rodrigo Vivi" <rodrigo.vivi@intel.com>,
"Simona Vetter" <simona@ffwll.ch>,
"Tvrtko Ursulin" <tursulin@ursulin.net>,
"Christian König" <christian.koenig@amd.com>,
"Thomas Hellström" <thomas.hellstrom@linux.intel.com>,
"Michał Winiarski" <michal.winiarski@intel.com>,
LKML <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 06/11] PCI: Fix restoring BARs on BAR resize rollback path
Date: Wed, 21 Jan 2026 12:02:35 +0200 (EET) [thread overview]
Message-ID: <bf1ece5f-07dd-31e7-db0d-40dfa8ebf7b7@linux.intel.com> (raw)
In-Reply-To: <aW_w1oFQCzUxGYtu@intel.com>
[-- Attachment #1: Type: text/plain, Size: 9727 bytes --]
On Tue, 20 Jan 2026, Ville Syrjälä wrote:
> On Thu, Nov 13, 2025 at 06:26:23PM +0200, Ilpo Järvinen wrote:
> > BAR resize operation is implemented in the pci_resize_resource() and
> > pbus_reassign_bridge_resources() functions. pci_resize_resource() can
> > be called either from __resource_resize_store() from sysfs or directly
> > by the driver for the Endpoint Device.
> >
> > The pci_resize_resource() requires that caller has released the device
> > resources that share the bridge window with the BAR to be resized as
> > otherwise the bridge window is pinned in place and cannot be changed.
> >
> > pbus_reassign_bridge_resources() implement rollback of the resources if
> > the resize operation fails, but rollback is performed only for the
> > bridge windows. Because releasing the device resources are done by the
> > caller of the BAR resize interface, these functions performing the BAR
> > resize do not have access to the device resources as they were before
> > the resize.
> >
> > pbus_reassign_bridge_resources() could try to
> > __pci_bridge_assign_resources() after rolling back the bridge windows
> > as they were, however, it will not guarantee the resource are assigned
> > due to differences how FW and the kernel may want to assign the
> > resources (alignment of the start address and tail).
> >
> > In order to perform rollback robustly, the BAR resize interface has to
> > be altered to also release the device resources that share the bridge
> > window with the BAR to be resized.
> >
> > Also, remove restoring from the entries failed list as saved list
> > should now contain both the bridge windows and device resources so
> > the extra restore is duplicated work.
> >
> > Some drivers (currently only amdgpu) want to prevent releasing some
> > resources. Add exclude_bars param to pci_resize_resource() and make
> > amdgpu to pass its register BAR (BAR 5) which should never be released
> > during resize operation. Normally 64-bit prefetchable resources do not
> > share bridge window with it as the register BAR (32-bit only) but there
> > are various fallbacks in the resource assignment logic which may make
> > the resources to share the bridge window in rare cases.
> >
> > This change (together with the driver side changes) is to counter the
> > resource releases that had to be done to prevent resource tree
> > corruption in the ("PCI: Release assigned resource before restoring
> > them") change. As such, it likely restores functionality in cases where
> > device resources were released to avoid resource tree conflicts which
> > appeared to be "working" when such conflicts were not correctly
> > detected by the kernel.
>
> This thing completely broke my DG2 + non-reBAR system. The bisect
> points to commit 4efaa80b3d75 ("drm/i915: Remove driver side BAR
> release before resize") but the real problems seem to be in this
> patch. A had a quick look at the code and spotted a few issues...
>
> <snip>
> > @@ -2468,34 +2466,78 @@ int pbus_reassign_bridge_resources(struct pci_bus *bus, struct resource *res)
> > free_list(&added);
> >
> > if (!list_empty(&failed)) {
> > - if (pci_required_resource_failed(&failed, type)) {
> > + if (pci_required_resource_failed(&failed, type))
> > ret = -ENOSPC;
> > - goto cleanup;
> > - }
> > - /* Only resources with unrelated types failed (again) */
> > free_list(&failed);
> > + if (ret)
> > + return ret;
> > +
> > + /* Only resources with unrelated types failed (again) */
> > }
> >
> > - list_for_each_entry(dev_res, &saved, list) {
> > + list_for_each_entry(dev_res, saved, list) {
> > struct pci_dev *dev = dev_res->dev;
> >
> > /* Skip the bridge we just assigned resources for */
> > if (bridge == dev)
> > continue;
> >
> > + if (!dev->subordinate)
> > + continue;
> > +
> > pci_setup_bridge(dev->subordinate);
> > }
> >
> > - free_list(&saved);
> > - up_read(&pci_bus_sem);
> > return 0;
> > +}
> >
> > -cleanup:
> > - /* Restore size and flags */
> > - list_for_each_entry(dev_res, &failed, list)
> > - restore_dev_resource(dev_res);
> > - free_list(&failed);
> > +int pci_do_resource_release_and_resize(struct pci_dev *pdev, int resno, int size,
> > + int exclude_bars)
> > +{
> > + struct resource *res = pci_resource_n(pdev, resno);
> > + struct pci_dev_resource *dev_res;
> > + struct pci_bus *bus = pdev->bus;
> > + struct resource *b_win, *r;
> > + LIST_HEAD(saved);
> > + unsigned int i;
> > + int ret = 0;
> > +
> > + b_win = pbus_select_window(bus, res);
> > + if (!b_win)
> > + return -EINVAL;
> > +
> > + pci_dev_for_each_resource(pdev, r, i) {
> > + if (i >= PCI_BRIDGE_RESOURCES)
> > + break;
> > +
> > + if (exclude_bars & BIT(i))
> > + continue;
> >
> > + if (b_win != pbus_select_window(bus, r))
> > + continue;
> > +
> > + ret = add_to_list(&saved, pdev, r, 0, 0);
> > + if (ret)
> > + goto restore;
> > + pci_release_resource(pdev, i);
> > + }
> > +
> > + pci_resize_resource_set_size(pdev, resno, size);
> > +
> > + if (!bus->self)
> > + goto out;
> > +
> > + down_read(&pci_bus_sem);
> > + ret = pbus_reassign_bridge_resources(bus, res, &saved);
> > + if (ret)
> > + goto restore;
> > +
> > +out:
> > + up_read(&pci_bus_sem);
> > + free_list(&saved);
> > + return ret;
> > +
> > +restore:
> > /* Revert to the old configuration */
> > list_for_each_entry(dev_res, &saved, list) {
> > struct resource *res = dev_res->res;
> > @@ -2510,13 +2552,21 @@ int pbus_reassign_bridge_resources(struct pci_bus *bus, struct resource *res)
> >
> > restore_dev_resource(dev_res);
> >
> > - pci_claim_resource(dev, i);
> > - pci_setup_bridge(dev->subordinate);
> > - }
> > - up_read(&pci_bus_sem);
> > - free_list(&saved);
> > + ret = pci_claim_resource(dev, i);
> > + if (ret)
> > + continue;
>
> This clobbers 'ret' was supposedly meant to be returned to the
> caller in the end. Thus (at least in my case) the caller always
> sees a return value of 0, and then it forgets to restores the
> reBAR setting back to the original value.
Thanks for the report.
Yes, you're right it's wrong, I'll move that call inside the if.
> > - return ret;
> > + if (i < PCI_BRIDGE_RESOURCES) {
> > + const char *res_name = pci_resource_name(dev, i);
> > +
> > + pci_update_resource(dev, i);
> > + pci_info(dev, "%s %pR: old value restored\n",
> > + res_name, res);
> > + }
> > + if (dev->subordinate)
> > + pci_setup_bridge(dev->subordinate);
> > + }
> > + goto out;
> > }
> >
> > void pci_assign_unassigned_bus_resources(struct pci_bus *bus)
> > diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
> > index 3d0b0b3f60c4..e4486d7030c0 100644
> > --- a/drivers/pci/setup-res.c
> > +++ b/drivers/pci/setup-res.c
> > @@ -444,8 +444,7 @@ static bool pci_resize_is_memory_decoding_enabled(struct pci_dev *dev,
> > return cmd & PCI_COMMAND_MEMORY;
> > }
> >
> > -static void pci_resize_resource_set_size(struct pci_dev *dev, int resno,
> > - int size)
> > +void pci_resize_resource_set_size(struct pci_dev *dev, int resno, int size)
> > {
> > resource_size_t res_size = pci_rebar_size_to_bytes(size);
> > struct resource *res = pci_resource_n(dev, resno);
> > @@ -456,9 +455,9 @@ static void pci_resize_resource_set_size(struct pci_dev *dev, int resno,
> > resource_set_size(res, res_size);
> > }
> >
> > -int pci_resize_resource(struct pci_dev *dev, int resno, int size)
> > +int pci_resize_resource(struct pci_dev *dev, int resno, int size,
> > + int exclude_bars)
> > {
> > - struct resource *res = pci_resource_n(dev, resno);
> > struct pci_host_bridge *host;
> > int old, ret;
> > u32 sizes;
> > @@ -468,10 +467,6 @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size)
> > if (host->preserve_config)
> > return -ENOTSUPP;
> >
> > - /* Make sure the resource isn't assigned before resizing it. */
> > - if (!(res->flags & IORESOURCE_UNSET))
> > - return -EBUSY;
> > -
> > if (pci_resize_is_memory_decoding_enabled(dev, resno))
> > return -EBUSY;
> >
> > @@ -490,19 +485,13 @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size)
> > if (ret)
> > return ret;
> >
> > - pci_resize_resource_set_size(dev, resno, size);
> > -
> > - /* Check if the new config works by trying to assign everything. */
> > - if (dev->bus->self) {
> > - ret = pbus_reassign_bridge_resources(dev->bus, res);
> > - if (ret)
> > - goto error_resize;
> > - }
> > + ret = pci_do_resource_release_and_resize(dev, resno, size, exclude_bars);
> > + if (ret)
> > + goto error_resize;
> > return 0;
> >
> > error_resize:
> > pci_rebar_set_size(dev, resno, old);
> > - pci_resize_resource_set_size(dev, resno, old);
>
> This new order is very broken because the new reBAR setting
> may have turned some of the originally set bits in the BAR
> to read-only. Thus we may not be able to restore the BAR back
> to the original value.
>
> In my case the original settings are 256MiB / 0x4030000000,
> followed by a failed resize to 8GiB, and finally we see a
> failed restore 'BAR 2: error updating (0x3000000c != 0x0000000c)'
> due to the read-only bits.
>
> i915 limps along after the failure but nothing really works,
> and xe just completely explodes.
Hmm, I certainly didn't foresee this happening. It seems I need to break
the nice rebar/setup-bus layering to fix this (by moving the
pci_rebar_set_size() calls into pci_do_resource_release_and_resize()).
--
i.
next prev parent reply other threads:[~2026-01-21 10:02 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20251113162628.5946-1-ilpo.jarvinen@linux.intel.com>
2025-11-13 16:26 ` [PATCH v2 01/11] PCI: Prevent resource tree corruption when BAR resize fails Ilpo Järvinen
2025-11-13 16:26 ` [PATCH v2 02/11] PCI/IOV: Adjust ->barsz[] when changing BAR size Ilpo Järvinen
2025-11-13 16:26 ` [PATCH v2 03/11] PCI: Change pci_dev variable from 'bridge' to 'dev' Ilpo Järvinen
2025-11-14 14:35 ` Alex Bennée
2025-11-13 16:26 ` [PATCH v2 04/11] PCI: Try BAR resize even when no window was released Ilpo Järvinen
2025-11-13 16:26 ` [PATCH v2 05/11] PCI: Freeing saved list does not require holding pci_bus_sem Ilpo Järvinen
2025-11-13 16:26 ` [PATCH v2 06/11] PCI: Fix restoring BARs on BAR resize rollback path Ilpo Järvinen
2025-11-13 16:46 ` Ilpo Järvinen
2025-11-13 21:01 ` Bjorn Helgaas
2025-11-14 9:34 ` Christian König
2026-01-20 21:17 ` Ville Syrjälä
2026-01-21 10:02 ` Ilpo Järvinen [this message]
2025-11-13 16:26 ` [PATCH v2 07/11] PCI: Add kerneldoc for pci_resize_resource() Ilpo Järvinen
2025-11-13 16:26 ` [PATCH v2 08/11] drm/xe: Remove driver side BAR release before resize Ilpo Järvinen
2025-11-14 13:10 ` Alex Bennée
2025-11-14 13:16 ` Ilpo Järvinen
2025-11-14 15:58 ` Lucas De Marchi
2025-11-13 16:26 ` [PATCH v2 09/11] drm/i915: " Ilpo Järvinen
2025-11-14 15:55 ` Lucas De Marchi
2025-11-13 16:26 ` [PATCH v2 10/11] drm/amdgpu: " Ilpo Järvinen
2025-11-13 16:26 ` [PATCH v2 11/11] PCI: Prevent restoring assigned resources Ilpo Järvinen
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=bf1ece5f-07dd-31e7-db0d-40dfa8ebf7b7@linux.intel.com \
--to=ilpo.jarvinen@linux.intel.com \
--cc=Simon.Richter@hogyros.de \
--cc=airlied@gmail.com \
--cc=alex.bennee@linaro.org \
--cc=alexander.deucher@amd.com \
--cc=amd-gfx@lists.freedesktop.org \
--cc=bhelgaas@google.com \
--cc=christian.koenig@amd.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=intel-gfx@lists.freedesktop.org \
--cc=intel-xe@lists.freedesktop.org \
--cc=jani.nikula@linux.intel.com \
--cc=joonas.lahtinen@linux.intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=lucas.demarchi@intel.com \
--cc=michal.winiarski@intel.com \
--cc=rodrigo.vivi@intel.com \
--cc=simona@ffwll.ch \
--cc=thomas.hellstrom@linux.intel.com \
--cc=tursulin@ursulin.net \
--cc=ville.syrjala@linux.intel.com \
/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