Skip to content

Commit 5528fd3

Browse files
ij-intelbjorn-helgaas
authored andcommitted
PCI: Fix Resizable BAR restore order
The commit 337b1b5 ("PCI: Fix restoring BARs on BAR resize rollback path") changed BAR resize to layer rebar code and resource setup/restore code cleanly. Unfortunately, it did not consider how the value of the BAR Size field impacts the read-only bits in the Base Address Register (PCIe7 spec, sec. 7.8.6.3). That is, it very much matters in which order the BAR Size and Base Address Register are restored. Post-337b1b566db0 ("PCI: Fix restoring BARs on BAR resize rollback path") during BAR resize rollback, pci_do_resource_release_and_resize() attempts to restore the old address to the BAR that was resized, but it can fail to setup the address correctly if the address has low bits set that collide with the bits that are still read-only. As a result, kernel's resource and BAR will be out-of-sync. Fix this by restoring BAR Size before rolling back the resource changes and restoring the BAR. Fixes: 337b1b5 ("PCI: Fix restoring BARs on BAR resize rollback path") Reported-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://lore.kernel.org/linux-pci/aW_w1oFQCzUxGYtu@intel.com/ Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Tested-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260121131417.9582-3-ilpo.jarvinen@linux.intel.com
1 parent 08d9eae commit 5528fd3

2 files changed

Lines changed: 19 additions & 19 deletions

File tree

drivers/pci/rebar.c

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,6 @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size,
295295
int exclude_bars)
296296
{
297297
struct pci_host_bridge *host;
298-
int old, ret;
299298

300299
/* Check if we must preserve the firmware's resource assignment */
301300
host = pci_find_host_bridge(dev->bus);
@@ -308,21 +307,6 @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size,
308307
if (!pci_rebar_size_supported(dev, resno, size))
309308
return -EINVAL;
310309

311-
old = pci_rebar_get_current_size(dev, resno);
312-
if (old < 0)
313-
return old;
314-
315-
ret = pci_rebar_set_size(dev, resno, size);
316-
if (ret)
317-
return ret;
318-
319-
ret = pci_do_resource_release_and_resize(dev, resno, size, exclude_bars);
320-
if (ret)
321-
goto error_resize;
322-
return 0;
323-
324-
error_resize:
325-
pci_rebar_set_size(dev, resno, old);
326-
return ret;
310+
return pci_do_resource_release_and_resize(dev, resno, size, exclude_bars);
327311
}
328312
EXPORT_SYMBOL(pci_resize_resource);

drivers/pci/setup-bus.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2504,12 +2504,20 @@ int pci_do_resource_release_and_resize(struct pci_dev *pdev, int resno, int size
25042504
struct resource *b_win, *r;
25052505
LIST_HEAD(saved);
25062506
unsigned int i;
2507-
int ret = 0;
2507+
int old, ret;
25082508

25092509
b_win = pbus_select_window(bus, res);
25102510
if (!b_win)
25112511
return -EINVAL;
25122512

2513+
old = pci_rebar_get_current_size(pdev, resno);
2514+
if (old < 0)
2515+
return old;
2516+
2517+
ret = pci_rebar_set_size(pdev, resno, size);
2518+
if (ret)
2519+
return ret;
2520+
25132521
pci_dev_for_each_resource(pdev, r, i) {
25142522
if (i >= PCI_BRIDGE_RESOURCES)
25152523
break;
@@ -2542,7 +2550,15 @@ int pci_do_resource_release_and_resize(struct pci_dev *pdev, int resno, int size
25422550
return ret;
25432551

25442552
restore:
2545-
/* Revert to the old configuration */
2553+
/*
2554+
* Revert to the old configuration.
2555+
*
2556+
* BAR Size must be restored first because it affects the read-only
2557+
* bits in BAR (the old address might not be restorable otherwise
2558+
* due to low address bits).
2559+
*/
2560+
pci_rebar_set_size(pdev, resno, old);
2561+
25462562
list_for_each_entry(dev_res, &saved, list) {
25472563
struct resource *res = dev_res->res;
25482564
struct pci_dev *dev = dev_res->dev;

0 commit comments

Comments
 (0)