From nobody Sat Sep 26 22:00:03 2026 Received: from mail-pl1-f171.google.com (mail-pl1-f171.google.com [209.85.214.171]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CA3087081A for ; Sat, 29 Aug 2026 00:43:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787964224; cv=none; b=t1bwj3rgIOxcqt6bGZ3TmzdgsxEB0iWsDxHaIru6Hjm1qXqZS6L33JgZnls783SJXbK9zY7fDLTUfZJpjFUOBRegp2g8iRbT6EyuMi0NOO2Ufm0yQ0pA07dXniwJvtX2m29d0rf6PtFOPi0FlHzQQhpFujtTDOZivpy0zeOmMoc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787964224; c=relaxed/simple; bh=vuQWjuWmc/4sF5KKA0zN5j2a6b7warJW3Qjsznw9VoM=; h=Message-ID:Date:MIME-Version:To:Cc:From:Subject:Content-Type; b=b0Fr42RtgYbyb57NMimoL/LlD+YXDAFCqax5iFO4KqoVWPVqfAyBRR54+7YEPaFxosUM9qYECdDQla4TbFuTFX29HxnTJoiQ4WG88hKzyOcdABPuOTSCKjr5yQxshduiuYW/WVFSl4wRM+NXPPXawi77yMCKwugEbceLS18/PAk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=jqluv.com; spf=none smtp.mailfrom=jqluv.com; dkim=pass (2048-bit key) header.d=jqluv-com.20251104.gappssmtp.com header.i=@jqluv-com.20251104.gappssmtp.com header.b=JLMTQU/S; arc=none smtp.client-ip=209.85.214.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=jqluv.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=jqluv.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=jqluv-com.20251104.gappssmtp.com header.i=@jqluv-com.20251104.gappssmtp.com header.b="JLMTQU/S" Received: by mail-pl1-f171.google.com with SMTP id d9443c01a7336-2d032846c95so17655445ad.1 for ; Fri, 28 Aug 2026 17:43:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jqluv-com.20251104.gappssmtp.com; s=20251104; t=1787964221; x=1788569021; darn=vger.kernel.org; h=content-transfer-encoding:content-type:subject:from:cc:to :content-language:user-agent:mime-version:date:message-id:from:to:cc :subject:date:message-id:reply-to:content-type; bh=uQpe6EYgnCeHFjzDxcLFZOag62YE7lR3UJLijS4+XTo=; b=JLMTQU/Suxj2V5ChDefQ2C0F+EXRnYNV6W8UfY+oyiwC3/L+DwZKQ10BfilCsVvjPk MFJXmxbcrsAgkO+t02Rvc0jXfKbSiFJtAYIsjRfEsz9GVfB272BENY7v5ZirPlK5SdX5 Ra2pC7R/3Cf949fc3ki2meUCGR0ScFTKtk+WIddWAHMpPIgpYTHgF01a926Lk81icK9O +iXhdquNUrAfAB0Sa9zizhN/QbmtYyPprYNy/FtGtWHuib6pbCfxH7jh4wxz1vdJ6VUw 0sFppFfWGs847xh1Rt7V8/IiukdufdPvRwaj3q7qRba212KXTVFURXAzynyKRlRPucLx 8m8w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787964221; x=1788569021; h=content-transfer-encoding:content-type:subject:from:cc:to :content-language:user-agent:mime-version:date:message-id:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=uQpe6EYgnCeHFjzDxcLFZOag62YE7lR3UJLijS4+XTo=; b=PWmmwvjhtkFjfuBiUz2xyVuq0hQe6eTi0TCtnbdPH3SetyLO9FD8rMkwg+HbxZ9qKd Fzyf+9FtIn0hiToizPimn6lDQKppq8Kw1qDaJ/8ZV3iyAOp/nLPxH0/GAGfb229JP5lH JfOZ9X9Io8IwP/pubr+tQjZ2MG/he+0tjdgtP8SWMHOtdsLzLxeKLSVG9s25HPDyfj+e h7flHnYtxrn4/V4hcluvU2Ew765mPFNOqa0vJI6qsY3Xxes+9oaTOXna57eUPAuJ28V4 ZlIyNwOpaN2k3lmrl4yfnewRTgfYcsmPymw3tdG9cuzW8rLWukGJWwfgc3U4/4LeJoO9 3YPg== X-Forwarded-Encrypted: i=1; AKwUvBxWCuZP0MC2K5pLZPhPNyq6gu/J8aH6fH5BaSyKb9L1/yWD9meIoeX+tYkpFc4E9Mgb0sc1CbNzxIZpVHM=@vger.kernel.org X-Gm-Message-State: AFuF++nXnubKuuG8h8h+T8mSB6iCMlVcP8AvmZZLqaSdX1CI3dmID1SM ld1vUJ/VWU9kCU5fGmOWev8qR7a3zs5uam+iKZovXU63cLCqsbcpNULmoWZZaroEszc= X-Gm-Gg: AYBFou14hetSlsiLTTLC+v3HbU17UvD2whp17MmNXOzR+0Mlr06nhkPACGVE1u/YtwM AiTNJ8zhDpLOyIlS6zLItJ7b4cqz8EnbVt5YSPFkEYAPDnPGXSlN7M+BzUQTBKt2+Ajju53AKXp W+XA0ZDS6D4yel0Dm3SiXrcy3bL3W8pLBiiZWaH8FJyHPlc2J57/bExngAviYJeMA8i5cLGDerC 5bn5P98KnPe2vWjgTaHDJUP6Mg3pslNW9JVb25wpCc6RQUdMtnw+N0JaKGZtr+9XuE4G5d2wKVo cz2IEPC9RR6nn6x3G5X52J0dLrmNXMMtrTVbODFZBgh8SKHNcUwkoZuSbKiQYSq8QXlbQaRRkUI J5/G4++ly078QKZvISpGVt7djT8CjIMz6NqdtIZkfyMrer8P5Sffuj7QMh6CbSTEDfE2QXJ4uoL mYSTOobKCaINFhj6E1utgKLRH0P7f5pPLJq1eHupHV6ekc7rPxSJ9nlogzIXBtVX6jmBG9ra1g1 h0ArS01T+GI7N56K4SXYnqaXBN9FtoNHAvsd9d+0uN/X8B2557YqpYgO5dWULqV3cHv X-Received: by 2002:a17:902:f688:b0:2d6:fee6:65ae with SMTP id d9443c01a7336-2d74dcafb41mr182731545ad.4.1787964220899; Fri, 28 Aug 2026 17:43:40 -0700 (PDT) Received: from ?IPV6:2601:201:8000:f750:9062:e94c:b180:8e48? ([2601:201:8000:f750:9062:e94c:b180:8e48]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3286f784845sm10884356eec.2.2026.08.28.17.43.39 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 28 Aug 2026 17:43:40 -0700 (PDT) Message-ID: <10fb16fb-2069-4d89-b473-1006ae5abfbc@jqluv.com> Date: Fri, 28 Aug 2026 17:43:38 -0700 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Content-Language: en-US To: Bjorn Helgaas Cc: alexander.deucher@amd.com, ilpo.jarvinen@linux.intel.com, amd-gfx@lists.freedesktop.org, mario.limonciello@amd.com, nra3088@gmail.com, =?UTF-8?Q?Christian_K=C3=B6nig?= , meiling.leung@embeddedllm.com, linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org From: Geramy Loveless Subject: [PATCH v3] PCI: Reserve prefetchable window headroom for Resizable BARs Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Firmware typically sizes prefetchable bridge windows for the boot-time BAR size. Behind a fixed (non-hotplug) PCIe switch fabric, there is then no room for a driver to grow a Resizable BAR afterwards: every window from the leaf up to the root is sized for the small BAR, so pci_resize_resource() fails with -ENOSPC.=20 Furthermore, a small prefetchable BAR (e.g., a 2 MiB doorbell) sharing a=20 bridge's single prefetchable window with a much larger one (e.g., a 32 GiB=20 VRAM BAR) pushes the required window size past the large BAR's alignment.=20 Because bridge windows round up to a power of two, this forces a massive=20 alignment waste (e.g., 32 GiB + 2 MiB rounds up to a 64 GiB window,=20 wasting ~32 GiB per GPU). This patch solves both issues to enable ReBAR on cascaded switch fabrics: 1. Reserve Headroom:=20 Reserve prefetchable window headroom for the maximum size of each=20 downstream Resizable BAR during the bridge sizing pass. The device BAR=20 and hardware ReBAR are left at their boot size to prevent tearing down=20 firmware-loaded state (e.g., AMD R9700 PSP) before the driver binds. 2. Pack Oversized Windows (BAR Demotion):=20 The PCI-to-PCI Bridge spec (r1.2, sec 3.2.5) permits a prefetchable BAR=20 to be assigned from the non-prefetchable window. By clearing the PREFETCH=20 flag on small control BARs during enumeration, they are placed below 4 GiB.=20 The prefetchable window is then cleanly sized to the large BAR alone. Why this is safe for 32-bit (< 4G) MMIO space: To prevent exhausting legacy < 4G space, demotion is strictly bounded. It=20 only triggers beside a massive prefetchable BAR (>=3D 64 MiB), and the demo= ted=20 BAR is strictly capped at 16 MiB (PCI_BAR_PACK_CAP). Even on an 8x GPU=20 system, this consumes at most 128 MiB of < 4G space.=20 Fallback / Alignment logic: If the 32-bit space is exhausted, small BARs remain in the prefetchable=20 window. The alignment logic gracefully handles this by rounding the bridge=20 window up to the next power of two (e.g., growing to 64 GiB to fit a 32 GiB=20 BAR + BAR2) to maintain PCIe compatibility, ensuring sibling GPUs land in=20 properly aligned slots. Reserving is safe by default: __assign_resources_sorted() satisfies all required resources first. Use pci=3Dno_rebar_reserve and pci=3Dno_bar_demot= e=20 to restore previous behaviours. Testing Context: - ASUS K14PG-D24 - 2x EPYC 9354 - 8x Radeon AI PRO R9700 (Navi 48, 1002:7551) - Broadcom PEX890xx switches - Kernel base: 45c13f3f9e3b (tested with SEV-SNP passthrough=3D1) Signed-off-by: Geramy Loveless --- .../admin-guide/kernel-parameters.txt | 9 ++ drivers/pci/pci.c | 15 ++ drivers/pci/pci.h | 2 + drivers/pci/quirks.c | 89 +++++++++++ drivers/pci/setup-bus.c | 142 ++++++++++++++++++ 5 files changed, 257 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentatio= n/admin-guide/kernel-parameters.txt index 37006fc3eac3..7360407dd4b8 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -5246,6 +5246,15 @@ Kernel parameters hpbussize=3Dnn The minimum amount of additional bus numbers reserved for buses below a hotplug bridge. Default is 1. + no_bar_demote Do not demote small prefetchable BARs below 4 GiB to pack = oversized prefetchable bridge windows. + no_rebar_reserve Do not reserve prefetchable bridge-window + space for the maximum size of downstream Resizable + BARs. By default such space is reserved so a driver + can grow a BAR later (e.g. GPU VRAM BAR) even behind + fixed PCIe switch fabrics that firmware sized for the + boot-time BAR; the device BAR is left at its boot size + for the driver to resize and only bridge windows are + enlarged. Use this to restore the old behaviour. realloc=3D Enable/disable reallocating PCI bridge resources if allocations done by BIOS are too small to accommodate resources required by all child diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b2879a6be5f8..0bb4ad570171 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -120,6 +120,17 @@ unsigned long pci_hotplug_mmio_pref_size =3D DEFAULT_H= OTPLUG_MMIO_PREF_SIZE; #define DEFAULT_HOTPLUG_BUS_SIZE 1 unsigned long pci_hotplug_bus_size =3D DEFAULT_HOTPLUG_BUS_SIZE; =20 +/* + * Prefetchable bridge-window headroom is reserved for the maximum size of + * downstream Resizable BARs by default, so a driver can grow one later + * (e.g. amdgpu VRAM BAR) even behind fixed PCIe switch fabrics. + * pci=3Dno_rebar_reserve disables this. + */ +bool pci_rebar_no_reserve; + +/* pci=3Dno_bar_demote disables demoting small prefetchable BARs below 4 G= iB. */ +bool pci_bar_demote_disabled; + =20 /* PCIe MPS/MRRS strategy; can be overridden by kernel command-line param = */ enum pcie_bus_config_types pcie_bus_config =3D PCIE_BUS_DEFAULT; @@ -6840,6 +6851,10 @@ static int __init pci_setup(char *str) simple_strtoul(str + 10, &str, 0); if (pci_hotplug_bus_size > 0xff) pci_hotplug_bus_size =3D DEFAULT_HOTPLUG_BUS_SIZE; + } else if (!strncmp(str, "no_rebar_reserve", 16)) { + pci_rebar_no_reserve =3D true; + } else if (!strncmp(str, "no_bar_demote", 13)) { + pci_bar_demote_disabled =3D true; } else if (!strncmp(str, "pcie_bus_tune_off", 17)) { pcie_bus_config =3D PCIE_BUS_TUNE_OFF; } else if (!strncmp(str, "pcie_bus_safe", 13)) { diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index ba3c3fddddc2..0f21972b674a 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -409,6 +409,8 @@ 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 bool pci_rebar_no_reserve; +extern bool pci_bar_demote_disabled; =20 static inline bool pci_is_cardbus_bridge(struct pci_dev *dev) { diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index de9bbccda21f..1094f618bb1f 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -6423,3 +6423,92 @@ static void pci_mask_replay_timer_timeout(struct pci= _dev *pdev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_t= imeout); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_t= imeout); #endif + +/* + * A small prefetchable BAR sharing a bridge's single prefetchable window = with a + * much larger one inflates that window past the large BAR's alignment. C= lear + * PREFETCH on such small BARs at enumeration so they land in the + * non-prefetchable window and the prefetchable window packs to the large = BAR + * alone. pci=3Dno_bar_demote disables this. + */ +#define PCI_BAR_PACK_MIN SZ_64M /* device must have a pref BAR at least th= is big */ +#define PCI_BAR_PACK_CAP SZ_16M /* only demote small pref BARs up to this = size */ + +/* Demote only if the host's 32-bit aperture has room (tracked per host). = */ +static bool pci_pack_low_reserve(struct pci_dev *dev, resource_size_t byte= s) +{ + static struct { struct pci_bus *root; u64 used; } budget[32]; + static int nbudget; + struct pci_bus *root =3D dev->bus; + struct resource *r; + u64 aperture =3D 0, *usedp =3D NULL; + int i; + + while (root->parent) + root =3D root->parent; + pci_bus_for_each_resource(root, r, i) { + if (r && (r->flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH)) =3D=3D + IORESOURCE_MEM && (u64)r->end < SZ_4G) + aperture +=3D resource_size(r); + } + if (!aperture) + return false; + + for (i =3D 0; i < nbudget; i++) { + if (budget[i].root =3D=3D root) { + usedp =3D &budget[i].used; + break; + } + } + if (!usedp) { + if (nbudget >=3D (int)ARRAY_SIZE(budget)) + return false; + budget[nbudget].root =3D root; + budget[nbudget].used =3D 0; + usedp =3D &budget[nbudget].used; + nbudget++; + } + if (*usedp + bytes > aperture / 2) + return false; + *usedp +=3D bytes; + return true; +} + +static void quirk_pci_pack_prefetch(struct pci_dev *dev) +{ + resource_size_t max_align =3D 0; + struct resource *r; + int i; + + if (pci_bar_demote_disabled) + return; + + for (i =3D 0; i < PCI_STD_NUM_BARS; i++) { + r =3D pci_resource_n(dev, i); + if ((r->flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH)) =3D=3D + (IORESOURCE_MEM | IORESOURCE_PREFETCH)) + max_align =3D max(max_align, pci_resource_alignment(dev, r)); + } + if (max_align < PCI_BAR_PACK_MIN) + return; + + for (i =3D 0; i < PCI_STD_NUM_BARS; i++) { + r =3D pci_resource_n(dev, i); + if ((r->flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH)) !=3D + (IORESOURCE_MEM | IORESOURCE_PREFETCH)) + continue; + if (r->flags & IORESOURCE_PCI_FIXED) + continue; + if (pci_resource_alignment(dev, r) >=3D max_align) + continue; /* an alignment-setting BAR, keep it */ + if (resource_size(r) > PCI_BAR_PACK_CAP) + continue; /* not a small control BAR */ + + if (!pci_pack_low_reserve(dev, resource_size(r))) + continue; /* no room below 4G: leave it prefetchable (fallback) */ + r->flags &=3D ~IORESOURCE_PREFETCH; + pci_info(dev, "%pR: assigned from the non-prefetchable window to pack th= e prefetchable window\n", + r); + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_pci_pack_prefetch); diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index e8c94aa1d3c1..d8b8cb35b8bb 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -1258,6 +1259,61 @@ static bool pbus_size_mem_optional(struct pci_dev *d= ev, int resno, return true; } =20 +/* + * pci_rebar_reserve_size - prefetchable window headroom to reserve for a = BAR + * + * Reserve enough prefetchable window space to later grow @resno of @dev to + * its maximum Resizable BAR size. This is done for every ReBAR-capable de= vice + * by default (disable with pci=3Dno_rebar_reserve). Only the optional (ad= d_size) + * part of the enclosing window is inflated here; the device BAR resource = and + * the hardware ReBAR are left at their boot size, so the driver still per= forms + * the actual resize into the reserved window. Reserving the window up fro= nt + * avoids -ENOSPC in pci_resize_resource() on fixed switch fabrics, where a + * window shared with a sibling's still-assigned BAR cannot be released and + * regrown at resize time. + * + * The reservation is strictly optional: __assign_resources_sorted() satis= fies + * all required resources first and only then places add_size on leftover + * space, so reserving by default cannot make a required BAR or window fai= l. + * + * Return the extra bytes to reserve and raise *add_align to the BAR's + * alignment so the reserved space can actually hold the grown BAR. + */ +/* roundup_pow_of_two() is unsigned long and truncates 64-bit sizes on 32-= bit. */ +static resource_size_t resource_size_roundup_pow2(resource_size_t n) +{ + if (n && (n & (n - 1))) + n =3D (resource_size_t)1 << fls64(n); + return n; +} + +static resource_size_t pci_rebar_reserve_size(struct pci_dev *dev, int res= no, + resource_size_t *add_align) +{ + struct resource *res =3D pci_resource_n(dev, resno); + resource_size_t max_size, cur_size; + int max; + + if (pci_rebar_no_reserve || resno >=3D PCI_STD_NUM_BARS) + return 0; + + if ((res->flags & (IORESOURCE_MEM_64 | IORESOURCE_PREFETCH)) !=3D + (IORESOURCE_MEM_64 | IORESOURCE_PREFETCH)) + return 0; + + max =3D pci_rebar_get_max_size(dev, resno); + if (max < 0) + return 0; + + max_size =3D pci_rebar_size_to_bytes(max); + cur_size =3D resource_size(res); + if (max_size <=3D cur_size) + return 0; + + *add_align =3D max(*add_align, max_size); + return max_size - cur_size; +} + /** * pbus_size_mem() - Size the memory window of a given bus * @@ -1285,6 +1341,7 @@ static void pbus_size_mem(struct pci_bus *bus, struct= resource *b_res, int order, max_order; resource_size_t children_add_size =3D 0; resource_size_t add_align =3D 0; + resource_size_t rebar_align =3D 0; =20 if (!b_res) return; @@ -1343,15 +1400,26 @@ static void pbus_size_mem(struct pci_bus *bus, stru= ct resource *b_res, aligns[order] +=3D align; if (order > max_order) max_order =3D order; + + children_add_size +=3D pci_rebar_reserve_size(dev, i, + &rebar_align); } } =20 win_align =3D pci_min_window_alignment(bus, b_res->flags); min_align =3D calculate_head_align(aligns, max_order); min_align =3D max(min_align, win_align); + min_align =3D max(min_align, rebar_align); size0 =3D calculate_memsize(size, realloc_head ? 0 : add_size, 0, win_align); =20 + /* + * Round a window sized above its own alignment up to a power of two + * >=3D its size, or siblings behind the same switch will not pack. + */ + if (rebar_align && size0) + min_align =3D max(min_align, resource_size_roundup_pow2(size0)); + if (size0) { resource_set_range(b_res, min_align, size0); b_res->flags &=3D ~IORESOURCE_DISABLED; @@ -2179,6 +2247,69 @@ static void pci_prepare_next_assign_round(struct lis= t_head *fail_head, * Second and later try will clear small leaf bridge res. * Will stop till to the max depth if can not find good one. */ +/* + * Release the 64-bit prefetchable BARs of resizable-BAR display devices s= o the + * windows enclosing them empty out and can be re-sized. The BAR *size* is= left + * untouched (only released and re-placed), so the hardware ReBAR is never + * programmed here - the driver still owns the actual resize. + */ +static int pci_release_pref_bars_cb(struct pci_dev *dev, void *data) +{ + struct resource *r; + unsigned int i; + + pci_dev_for_each_resource(dev, r, i) { + if (i >=3D PCI_BRIDGE_RESOURCES) + break; + if (r->parent && (r->flags & IORESOURCE_MEM_64) && + (r->flags & IORESOURCE_PREFETCH)) + pci_release_resource(dev, i); + } + return 0; +} + +/* True if the subtree holds a display device with a growable Resizable BA= R. */ +static bool pci_bus_needs_rebar_regrow(struct pci_bus *bus) +{ + struct pci_dev *dev; + int i, max; + + list_for_each_entry(dev, &bus->devices, bus_list) { + if ((dev->class >> 16) =3D=3D PCI_BASE_CLASS_DISPLAY) + for (i =3D 0; i < PCI_STD_NUM_BARS; i++) { + max =3D pci_rebar_get_max_size(dev, i); + if (max >=3D 0 && + max > pci_rebar_get_current_size(dev, i)) + return true; + } + if (dev->subordinate && + pci_bus_needs_rebar_regrow(dev->subordinate)) + return true; + } + return false; +} + +/* + * Release the now-empty prefetchable bridge windows bottom-up so the sizi= ng + * pass re-sizes them (with pci_rebar_pref_reserve() reservation) to fit t= he + * BARs a driver will later grow. + */ +static void pci_release_rebar_windows(struct pci_bus *bus) +{ + struct pci_dev *dev; + struct resource *w; + + list_for_each_entry(dev, &bus->devices, bus_list) + if (dev->subordinate) + pci_release_rebar_windows(dev->subordinate); + + if (!bus->self) + return; + w =3D &bus->self->resource[PCI_BRIDGE_PREF_MEM_WINDOW]; + if (w->parent && (w->flags & IORESOURCE_MEM_64) && !w->child) + pci_release_resource(bus->self, PCI_BRIDGE_PREF_MEM_WINDOW); +} + void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus) { LIST_HEAD(realloc_head); @@ -2190,6 +2321,17 @@ void pci_assign_unassigned_root_bus_resources(struct= pci_bus *bus) int pci_try_num =3D 1; enum enable_type enable_local; =20 + /* + * Release resizable device BARs and their prefetchable windows so the + * sizing pass re-sizes those windows large enough (pci_rebar_pref_reserv= e) + * for the BARs a driver will later grow. Only released and re-placed - t= he + * BAR size is left untouched, so the hardware ReBAR is never programmed. + */ + if (pci_bus_needs_rebar_regrow(bus)) { + pci_walk_bus(bus, pci_release_pref_bars_cb, NULL); + pci_release_rebar_windows(bus); + } + /* Don't realloc if asked to do so */ enable_local =3D pci_realloc_detect(bus, pci_realloc_enable); if (pci_realloc_enabled(enable_local)) { base-commit: 45c13f3f9e3bb15fd89ff2864c6f627a3b4b4229 --=20 2.53.0