diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-20 16:57:59 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-20 16:57:59 -0700 |
| commit | a625b2a387628df94e385faf5c81bf252f304ed9 (patch) | |
| tree | e3be1a5a3d57d45aea64e977827d2fd9c6adfd7a /drivers/vfio | |
| parent | 77ae27fd98f3b548797c9f22c10ab5cf1c4ada53 (diff) | |
| parent | 4e3c1fc8abcb8eff062150b4340fa4569696d645 (diff) | |
| download | linux-next-a625b2a387628df94e385faf5c81bf252f304ed9.tar.gz linux-next-a625b2a387628df94e385faf5c81bf252f304ed9.zip | |
Merge tag 'vfio-v7.3-rc1' of https://github.com/awilliam/linux-vfio
Pull VFIO updates from Alex Williamson:
- Add nv_falcon vfio selftest driver.
The Falcon is a general-purpose microcontroller embedded within
NVIDIA GPUs, presenting a relatively simple DMA programming
interface.
This adds another selftest target for vfio-pci with real DMA
transfers (Rubin Du, Alex Williamson)
- Add allocation assertion helpers to vfio selftests and use them to
avoid variable length arrays and the compiler errors they generate
(Alex Mastro)
- Fix use-after-free hazard where an init path error in MSI support
leaves a stray pointer that can later be reused or double-freed
(Xiang Mei)
- Fix previous refactor of PCI BAR mappings to honor non_mappable_bars
flag, which otherwise generates a warning when trying to pci_iomap()
a 256TiB BAR on ISM devices on s390 (Farhan Ali)
- Add igb vfio selftest driver.
Like nv_falcon, this provides another target for DMA testing with
vfio selftests, but importantly this driver supports both physical
82576 NICs and the emulation model in QEMU.
This therefore enables a vfio selftest vector with no physical
hardware requirements (Josh Hilke, Alex Williamson)
- Mark selftest fixture objects __maybe_unused to accommodate builds
with clang -Wunused-but-set-global (David Matlack)
- Add error recovery for vfio-pci devices on s390x.
This expands devices which expose the existing error eventfd and
introduces a device feature for reporting firmware defined error
state information to the user, allowing recovery through hypervisor
channels (Farhan Ali)
* tag 'vfio-v7.3-rc1' of https://github.com/awilliam/linux-vfio:
vfio/pci: Remove the pcie check for VFIO_PCI_ERR_IRQ_INDEX
vfio-pci/zdev: Add a device feature for error information
s390/pci: Store PCI error information for passthrough devices
PCI/MSI: Enable memory decoding before restoring MSI-X messages
PCI: Fail FLR when config space is inaccessible
PCI: Avoid saving config space state if inaccessible
PCI: Allow per function PCI slots to fix slot reset on s390
PCI: Introduce PCI_SLOT_PLACEHOLDER constant for slot_nr placeholder value
selftests: harness: Mark test fixture objects __maybe_unused
vfio: selftests: Retry on EAGAIN during device reset
vfio: selftests: igb: Add driver for Intel 82576 device
vfio: selftests: Add helpers to re-enable interrupts
vfio/pci: Avoid mapping BARs for devices with non-mappable BARs
vfio/pci: clear vdev->msi_perm after freeing it on init failure
vfio: selftests: Avoid VLAs
vfio: selftests: Add allocation assert helpers
vfio: selftests: Add NVIDIA Falcon driver for DMA testing
vfio: selftests: Allow drivers without send_msi() support
vfio: selftests: Add generic PCI command register helpers
vfio: selftests: Add memcpy chunking to vfio_pci_driver_memcpy()
Diffstat (limited to 'drivers/vfio')
| -rw-r--r-- | drivers/vfio/pci/vfio_pci_config.c | 1 | ||||
| -rw-r--r-- | drivers/vfio/pci/vfio_pci_core.c | 13 | ||||
| -rw-r--r-- | drivers/vfio/pci/vfio_pci_intrs.c | 3 | ||||
| -rw-r--r-- | drivers/vfio/pci/vfio_pci_priv.h | 9 | ||||
| -rw-r--r-- | drivers/vfio/pci/vfio_pci_zdev.c | 62 |
5 files changed, 75 insertions, 13 deletions
diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index a10ed733f0e3..9914f3ac69ae 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c @@ -1272,6 +1272,7 @@ static int vfio_msi_cap_len(struct vfio_pci_core_device *vdev, u8 pos) ret = init_pci_cap_msi_perm(vdev->msi_perm, len, flags); if (ret) { kfree(vdev->msi_perm); + vdev->msi_perm = NULL; return ret; } diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c index 3f11a9624b9c..362c375a0579 100644 --- a/drivers/vfio/pci/vfio_pci_core.c +++ b/drivers/vfio/pci/vfio_pci_core.c @@ -554,6 +554,9 @@ static void vfio_pci_core_map_bars(struct vfio_pci_core_device *vdev) vdev->barmap[bar] = IOMEM_ERR_PTR(-ENODEV); + if (pdev->non_mappable_bars) + continue; + if (!pci_resource_len(pdev, i)) continue; @@ -877,8 +880,7 @@ static int vfio_pci_get_irq_count(struct vfio_pci_core_device *vdev, int irq_typ return (flags & PCI_MSIX_FLAGS_QSIZE) + 1; } } else if (irq_type == VFIO_PCI_ERR_IRQ_INDEX) { - if (pci_is_pcie(vdev->pdev)) - return 1; + return 1; } else if (irq_type == VFIO_PCI_REQ_IRQ_INDEX) { return 1; } @@ -1254,11 +1256,8 @@ static int vfio_pci_ioctl_get_irq_info(struct vfio_pci_core_device *vdev, switch (info.index) { case VFIO_PCI_INTX_IRQ_INDEX ... VFIO_PCI_MSIX_IRQ_INDEX: case VFIO_PCI_REQ_IRQ_INDEX: - break; case VFIO_PCI_ERR_IRQ_INDEX: - if (pci_is_pcie(vdev->pdev)) - break; - fallthrough; + break; default: return -EINVAL; } @@ -1625,6 +1624,8 @@ int vfio_pci_core_ioctl_feature(struct vfio_device *device, u32 flags, return vfio_pci_core_feature_token(vdev, flags, arg, argsz); case VFIO_DEVICE_FEATURE_DMA_BUF: return vfio_pci_core_feature_dma_buf(vdev, flags, arg, argsz); + case VFIO_DEVICE_FEATURE_ZPCI_ERROR: + return vfio_pci_zdev_feature_err(device, flags, arg, argsz); default: return -ENOTTY; } diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c index 33944d4d9dc4..64f80f64ff57 100644 --- a/drivers/vfio/pci/vfio_pci_intrs.c +++ b/drivers/vfio/pci/vfio_pci_intrs.c @@ -859,8 +859,7 @@ int vfio_pci_set_irqs_ioctl(struct vfio_pci_core_device *vdev, uint32_t flags, case VFIO_PCI_ERR_IRQ_INDEX: switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) { case VFIO_IRQ_SET_ACTION_TRIGGER: - if (pci_is_pcie(vdev->pdev)) - func = vfio_pci_set_err_trigger; + func = vfio_pci_set_err_trigger; break; } break; diff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h index fca9d0dfac90..4e7162234a2e 100644 --- a/drivers/vfio/pci/vfio_pci_priv.h +++ b/drivers/vfio/pci/vfio_pci_priv.h @@ -93,6 +93,8 @@ int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, struct vfio_info_cap *caps); int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev); void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev); +int vfio_pci_zdev_feature_err(struct vfio_device *device, u32 flags, + void __user *arg, size_t argsz); #else static inline int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, struct vfio_info_cap *caps) @@ -107,6 +109,13 @@ static inline int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev) static inline void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev) {} + +static inline int vfio_pci_zdev_feature_err(struct vfio_device *device, + u32 flags, void __user *arg, + size_t argsz) +{ + return -ENOTTY; +} #endif static inline bool vfio_pci_is_vga(struct pci_dev *pdev) diff --git a/drivers/vfio/pci/vfio_pci_zdev.c b/drivers/vfio/pci/vfio_pci_zdev.c index 0990fdb146b7..f47f36314a1c 100644 --- a/drivers/vfio/pci/vfio_pci_zdev.c +++ b/drivers/vfio/pci/vfio_pci_zdev.c @@ -24,7 +24,7 @@ static int zpci_base_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps) { struct vfio_device_info_cap_zpci_base cap = { .header.id = VFIO_DEVICE_INFO_CAP_ZPCI_BASE, - .header.version = 2, + .header.version = 3, .start_dma = zdev->start_dma, .end_dma = zdev->end_dma, .pchid = zdev->pchid, @@ -32,7 +32,8 @@ static int zpci_base_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps) .fmb_length = zdev->fmb_length, .pft = zdev->pft, .gid = zdev->pfgid, - .fh = zdev->fh + .fh = zdev->fh, + .ccdf_err_length = sizeof(struct zpci_ccdf_err) }; return vfio_info_add_capability(caps, &cap.header, sizeof(cap)); @@ -141,27 +142,78 @@ int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, return ret; } +int vfio_pci_zdev_feature_err(struct vfio_device *device, u32 flags, + void __user *arg, size_t argsz) +{ + struct vfio_device_feature_zpci_err err; + struct vfio_pci_core_device *vdev; + struct zpci_ccdf_err ccdf = {}; + struct zpci_dev *zdev; + int ret; + + vdev = container_of(device, struct vfio_pci_core_device, vdev); + zdev = to_zpci(vdev->pdev); + if (!zdev) + return -ENODEV; + + ret = vfio_check_feature(flags, argsz, VFIO_DEVICE_FEATURE_GET, + sizeof(err)); + if (ret != 1) + return ret; + + if (copy_from_user(&err, arg, sizeof(err))) + return -EFAULT; + + if (!err.data) + return -EINVAL; + + ret = zpci_get_pending_error(zdev, &ccdf); + if (ret) + return ret; + + if (copy_to_user(u64_to_user_ptr(err.data), &ccdf, sizeof(ccdf))) { + dev_warn_ratelimited(device->dev, + "Failed to handle PCI error event for PCI function 0x%x", + zdev->fid); + return -EFAULT; + } + + return 0; +} + int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev) { struct zpci_dev *zdev = to_zpci(vdev->pdev); + int ret; if (!zdev) return -ENODEV; + zpci_start_mediated_recovery(zdev); + if (!vdev->vdev.kvm) return 0; + ret = -ENOENT; if (zpci_kvm_hook.kvm_register) - return zpci_kvm_hook.kvm_register(zdev, vdev->vdev.kvm); + ret = zpci_kvm_hook.kvm_register(zdev, vdev->vdev.kvm); + + if (ret) + zpci_stop_mediated_recovery(zdev); - return -ENOENT; + return ret; } void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev) { struct zpci_dev *zdev = to_zpci(vdev->pdev); - if (!zdev || !vdev->vdev.kvm) + if (!zdev) + return; + + zpci_stop_mediated_recovery(zdev); + + if (!vdev->vdev.kvm) return; if (zpci_kvm_hook.kvm_unregister) |
