summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-01-23 13:20:24 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2026-01-23 13:20:24 -0800
commit5bde837031a3e0465b8c8413d45e45d7927b958a (patch)
tree7d701eeaa3624977e70b182ca8d4d7484704f7cb
parent2a4d91142e538ff5580c6bf48b5e668d8131fd9a (diff)
parent5528fd38f230c906fcebb202cc94fbb8ed8f122a (diff)
downloadlinux-5bde837031a3e0465b8c8413d45e45d7927b958a.tar.gz
linux-5bde837031a3e0465b8c8413d45e45d7927b958a.tar.bz2
linux-5bde837031a3e0465b8c8413d45e45d7927b958a.zip
Merge tag 'pci-v6.19-fixes-4' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci
Pull PCI fixes from Bjorn Helgaas: - Fix the pci_do_resource_release_and_resize() failure path, which clobbered the intended failure return value (Ilpo Järvinen) - Restore resizable BAR size before value because the size determines which bits are writable; this fixes i915 and xe regressions (Ilpo Järvinen) * tag 'pci-v6.19-fixes-4' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci: PCI: Fix Resizable BAR restore order PCI: Fix BAR resize rollback path overwriting ret
-rw-r--r--drivers/pci/rebar.c18
-rw-r--r--drivers/pci/setup-bus.c23
2 files changed, 20 insertions, 21 deletions
diff --git a/drivers/pci/rebar.c b/drivers/pci/rebar.c
index ecdebdeb2dff..39f8cf3b70d5 100644
--- a/drivers/pci/rebar.c
+++ b/drivers/pci/rebar.c
@@ -295,7 +295,6 @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size,
int exclude_bars)
{
struct pci_host_bridge *host;
- int old, ret;
/* Check if we must preserve the firmware's resource assignment */
host = pci_find_host_bridge(dev->bus);
@@ -308,21 +307,6 @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size,
if (!pci_rebar_size_supported(dev, resno, size))
return -EINVAL;
- old = pci_rebar_get_current_size(dev, resno);
- if (old < 0)
- return old;
-
- ret = pci_rebar_set_size(dev, resno, size);
- if (ret)
- return ret;
-
- 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);
- return ret;
+ return pci_do_resource_release_and_resize(dev, resno, size, exclude_bars);
}
EXPORT_SYMBOL(pci_resize_resource);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 6e90f46f52af..a61d38777cdc 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -2504,12 +2504,20 @@ int pci_do_resource_release_and_resize(struct pci_dev *pdev, int resno, int size
struct resource *b_win, *r;
LIST_HEAD(saved);
unsigned int i;
- int ret = 0;
+ int old, ret;
b_win = pbus_select_window(bus, res);
if (!b_win)
return -EINVAL;
+ old = pci_rebar_get_current_size(pdev, resno);
+ if (old < 0)
+ return old;
+
+ ret = pci_rebar_set_size(pdev, resno, size);
+ if (ret)
+ return ret;
+
pci_dev_for_each_resource(pdev, r, i) {
if (i >= PCI_BRIDGE_RESOURCES)
break;
@@ -2542,7 +2550,15 @@ out:
return ret;
restore:
- /* Revert to the old configuration */
+ /*
+ * Revert to the old configuration.
+ *
+ * BAR Size must be restored first because it affects the read-only
+ * bits in BAR (the old address might not be restorable otherwise
+ * due to low address bits).
+ */
+ pci_rebar_set_size(pdev, resno, old);
+
list_for_each_entry(dev_res, &saved, list) {
struct resource *res = dev_res->res;
struct pci_dev *dev = dev_res->dev;
@@ -2556,8 +2572,7 @@ restore:
restore_dev_resource(dev_res);
- ret = pci_claim_resource(dev, i);
- if (ret)
+ if (pci_claim_resource(dev, i))
continue;
if (i < PCI_BRIDGE_RESOURCES) {