[RFC PATCH v3 00/20] vfio/pci: Handle PCI error recovery and report state to userspace

From: Shameer Kolothum

Date: Thu Nov 12 2026 - 09:33:55 EST


Hi,

Currently, vfio-pci signals the error eventfd from error_detected() and
returns PCI_ERS_RESULT_CAN_RECOVER, including for permanent failure. It
has no slot_reset() or resume() callback, so userspace is not notified
when host recovery completes or whether the device was reset.

This series adds opt-in host PCI error recovery for vfio-pci. It blocks
device access during recovery, restores device state after a host reset,
and reports recovery status to userspace. The kernel runs host recovery
and the VMM decides how to recover the guest.

Major Changes from v2:
v2: https://lore.kernel.org/kvm/20260929173305.204856-1-skolothumtho@xxxxxxxxxx/

- Rework device access serialization around live and blocked access ops,
using SRCU to drain ongoing accesses before recovery.
- Address the D0 bus-lock cycle described in RFC v2. Add
pci_try_set_power_state() for ordinary transitions and use the locked
helper during recovery to avoid taking pci_bus_sem again.
- Fix INTx restoration ordering, recovery status reporting and PF access
during VF information queries.
- Limit enablement to supported native PCIe recovery paths. Exclude
functions with VPD redirected to function zero, and Intel Ethernet
function zero devices with VPD.

Design
------
Userspace opts in through VFIO_DEVICE_FEATURE_PCI_ERROR_RECOVERY. It
registers an eventfd and reads status flags and a sequence number. The
existing error eventfd is still signaled.

The callbacks handle the host recovery sequence:

- error_detected() blocks new accesses and drains admitted ones,
quiesces INTx, and revokes BAR mappings and exported DMA-BUFs. On a
normal channel it also clears bus mastering. It votes CAN_RECOVER
for a normal channel, NEED_RESET for a frozen channel, and DISCONNECT
for permanent failure. Failure to save PCI_COMMAND or disable bus
mastering leaves access blocked and returns NONE so other devices
can continue recovery.
- slot_reset() restores the configuration saved at open after a host
reset, then tears down interrupt configuration. Userspace must set
up interrupts again.
- resume() completes restoration, unblocks access and completes INTx
handling. A restoration failure keeps the device blocked.

Non-fatal errors also block device access because host recovery may
require a reset. Userspace reads the recovery status to determine
whether the device was reset or recovery failed.

Without opt-in, the existing error notification behavior is retained.
Open also rejects attempts while a recorded host recovery is in progress,
even when userspace has not enabled recovery.

Locking and open questions
-------------------------

PCI core holds device_lock during recovery callbacks and pci_bus_sem
for reading during the supported recovery walk.

VFIO uses access_lock to serialize recovery and switch access ops.
Recovery blocks new accesses and waits for existing SRCU readers to
finish. Switching ops also takes irqlock to serialize with INTx
callbacks, which do not use SRCU. Power transitions and mapping
changes use memory_lock.

The D0 bus-lock cycle described in RFC v2 is addressed by the try-lock
helper for ordinary transitions and the locked helper in recovery. This
uses the locking provided by the supported native PCI bus walk. It does
not impose a new locking requirement on every PCI recovery dispatcher.

Pre-existing(Sashiko reported):
--------------
- Open and close were not serialized with the whole host recovery
transaction before this series. That remains the case. Recovery
can start after the open check, and close can overlap the
physical reset. Restoration of closed devices is also still
missing.

LLM tools assisted with implementation. I also ran local Sashiko
reviews.

Testing
-------
Basic sanity tests performed on a GB200 with an NVIDIA GPU assigned.

Kernel branch:
https://github.com/shamiali2008/linux/tree/vfio-aer-rfc-v3-ext

QEMU test branch is here(This registers the recovery eventfd and uses
pcie_aer_inject_error() to report the error to Guest)
https://github.com/shamiali2008/qemu-master/commits/private-master-vfio-aer-test-v2/

Software AER injection was performed using a modified pcieaer_inject
module.

./aer-inject nonfatal.conf

qemu-system-aarch64: info: vfio 0018:06:00.0: host PCI error recovery completed (seq 1)

Guest kernel:

[ 59.036988] pcieport 0000:01:00.0: AER: Uncorrectable (Non-Fatal) error message received from 0000:02:00.0
[ 59.038326] nvidia 0000:02:00.0: PCIe Bus Error: severity=Uncorrectable (Non-Fatal), type=Transaction Layer, (Completer ID)
[ 59.038440] nvidia 0000:02:00.0: device [10de:2941] error status/mask=00008000/02400000
[ 59.038533] nvidia 0000:02:00.0: [15] CmpltAbrt (First)
[ 59.038705] nvidia 0000:02:00.0: AER: TLP Header: 0x00000000 0x00000000 0x00000000 0x00000000
...

./aer-inject fatal.conf
qemu-system-aarch64: info: vfio 0018:06:00.0: host PCI error recovery started (seq 2, channel frozen)
qemu-system-aarch64: info: vfio 0018:06:00.0: host PCI error recovery completed (seq 2, device was reset)

Guest kernel:

[ 150.909306] pcieport 0000:01:00.0: AER: Uncorrectable (Fatal) error message received from 0000:02:00.0
[ 150.909566] nvidia 0000:02:00.0: AER: PCIe Bus Error: severity=Uncorrectable (Fatal), type=Inaccessible, (Unregistered Agent ID)
[ 150.909835] nvidia 0000:02:00.0: AER: can't recover (no error_detected callback)
[ 150.910062] pcieport 0000:01:00.0: unlocked secondary bus reset via: pciehp_reset_slot+0x54/0x98
[ 156.603467] pcieport 0000:01:00.0: AER: Root Port link has been reset (0)
...

Please take a look and let me know your feedback.

Thanks,
Shameer


Shameer Kolothum (20):
vfio/pci: Add SRCU-protected access ops
PCI/PM: Add a power-state helper that tries the bus lock
vfio/pci: Avoid waiting for the bus lock when preparing D0
vfio/pci: Use access ops for config-space accesses
vfio/pci: Buffer ROM reads before copying to userspace
vfio/pci: Use access ops for BAR and ROM accesses
vfio/pci: Use access ops when mapping BAR pages
vfio/pci: Use access ops for hardware IRQ operations
vfio/pci: Use access ops for function reset
vfio/pci: Use access ops for runtime-PM requests
vfio/pci: Use access ops for hardware information queries
vfio/pci: Use access ops for DMA-BUF export and restoration
vfio/pci: Track PCI recovery state
vfio/pci: Add INTx recovery operations
vfio/pci: Use access ops for SR-IOV configuration and shared reset
vfio/pci: Restore device state from slot_reset()
vfio/pci: Complete recovery in resume()
vfio/pci: Block device access during host recovery
vfio/pci: Add VFIO_DEVICE_FEATURE_PCI_ERROR_RECOVERY
vfio/pci: Enable recovery for supported native PCIe endpoints

drivers/vfio/pci/vfio_pci_priv.h | 58 ++
include/linux/pci.h | 3 +
include/linux/vfio_pci_core.h | 36 +-
include/uapi/linux/vfio.h | 55 ++
drivers/pci/pci.c | 37 ++
drivers/vfio/pci/vfio_pci.c | 88 ++-
drivers/vfio/pci/vfio_pci_config.c | 122 +++-
drivers/vfio/pci/vfio_pci_core.c | 955 +++++++++++++++++++++++++++--
drivers/vfio/pci/vfio_pci_dmabuf.c | 113 ++--
drivers/vfio/pci/vfio_pci_intrs.c | 183 +++++-
drivers/vfio/pci/vfio_pci_rdwr.c | 297 ++++++---
11 files changed, 1705 insertions(+), 242 deletions(-)

--
2.43.0