[+cc Thorsten, thanks for the reminder!]
On Wed, Apr 15, 2026 at 05:56:06PM +0200, Lukas Wunner wrote:
> Bernd reports passthrough failure of a Digital Devices Cine S2 V6 DVB
> adapter plugged into an ASRock X570S PG Riptide board with BIOS version
> P5.41 (09/07/2023):
>
> ddbridge 0000:05:00.0: detected Digital Devices Cine S2 V6 DVB adapter
> ddbridge 0000:05:00.0: cannot read registers
> ddbridge 0000:05:00.0: fail
>
> BIOS assigns an incorrect BAR to the DVB adapter which doesn't fit into
> the upstream bridge window. The kernel corrects the BAR assignment:
>
> pci 0000:07:00.0: BAR 0 [mem 0xfffffffffc500000-0xfffffffffc50ffff 64bit]:
> can't claim; no compatible bridge window
> pci 0000:07:00.0: BAR 0 [mem 0xfc500000-0xfc50ffff 64bit]: assigned
>
> Correction of the BAR assignment happens in an x86-specific fs_initcall,
> pcibios_assign_resources(), after device enumeration in a subsys_initcall.
> This order was introduced at the behest of Linus in 2004:
>
> https://git.kernel.org/tglx/history/c/a06a30144bbc
>
> No other architecture performs such a late BAR correction.
>
> Bernd bisected the issue to commit a2f1e22390ac ("PCI/ERR: Ensure error
> recoverability at all times"), but it only occurs in the absence of commit
> 4d4c10f763d7 ("PCI: Explicitly put devices into D0 when initializing").
> This combination exists in stable kernel v6.12.70, but not in mainline,
> hence Bernd cannot reproduce the issue with mainline.
>
> Since a2f1e22390ac, config space is saved on enumeration, prior to BAR
> correction. Upon passthrough, the corrected BAR is overwritten with the
> incorrect saved value by:
>
> vfio_pci_core_register_device()
> vfio_pci_set_power_state()
> pci_restore_state()
>
> But only if the device's current_state is PCI_UNKNOWN, as it was prior to
> commit 4d4c10f763d7. Since the commit, it is PCI_D0, which changes the
> behavior of vfio_pci_set_power_state() to no longer restore the state
> without saving it first.
>
> Alexandre is reporting the same issue as Bernd, but in his case, mainline
> is affected as well. The difference is that on Alexandre's system, the
> host kernel binds a driver to the device which is unbound prior to
> passthrough, whereas on Bernd's system no driver gets bound by the host
> kernel.
>
> Unbinding sets current_state to PCI_UNKNOWN in pci_device_remove(), so
> when vfio-pci is subsequently bound to the device, pci_restore_state() is
> once again called without invoking pci_save_state() first.
>
> To robustly fix the issue, always update saved_config_space upon resource
> assignment.
>
> Reported-by: Bernd Schumacher <[email protected]>
> Tested-by: Bernd Schumacher <[email protected]>
> Closes: https://lore.kernel.org/r/[email protected]/
> Reported-by: Alexandre N. <[email protected]>
> Tested-by: Alexandre N. <[email protected]>
> Closes:
> https://lore.kernel.org/r/[email protected]/
> Fixes: a2f1e22390ac ("PCI/ERR: Ensure error recoverability at all times")
> Signed-off-by: Lukas Wunner <[email protected]>
> Cc: [email protected] # v6.12+
a2f1e22390ac appeared in v6.19. Applied this fix to pci/for-linus for
v7.1, thanks!
> ---
> drivers/pci/setup-res.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
> index e5fcadf..1769ba9 100644
> --- a/drivers/pci/setup-res.c
> +++ b/drivers/pci/setup-res.c
> @@ -102,6 +102,7 @@ static void pci_std_update_resource(struct pci_dev *dev,
> int resno)
> }
>
> pci_write_config_dword(dev, reg, new);
> + dev->saved_config_space[reg / 4] = new;
> pci_read_config_dword(dev, reg, &check);
>
> if ((new ^ check) & mask) {
> @@ -112,6 +113,7 @@ static void pci_std_update_resource(struct pci_dev *dev,
> int resno)
> if (res->flags & IORESOURCE_MEM_64) {
> new = region.start >> 16 >> 16;
> pci_write_config_dword(dev, reg + 4, new);
> + dev->saved_config_space[(reg + 4) / 4] = new;
> pci_read_config_dword(dev, reg + 4, &check);
> if (check != new) {
> pci_err(dev, "%s: error updating (high %#010x !=
> %#010x)\n",
> --
> 2.51.0
>