diff options
| -rw-r--r-- | Documentation/ABI/testing/debugfs-vfio | 26 | ||||
| -rw-r--r-- | drivers/vfio/debugfs.c | 1 | ||||
| -rw-r--r-- | drivers/vfio/pci/mlx5/cmd.h | 15 | ||||
| -rw-r--r-- | drivers/vfio/pci/vfio_pci.c | 30 | ||||
| -rw-r--r-- | drivers/vfio/pci/vfio_pci_core.c | 101 | ||||
| -rw-r--r-- | drivers/vfio/vfio_main.c | 8 | ||||
| -rw-r--r-- | include/linux/vfio_pci_core.h | 18 | ||||
| -rw-r--r-- | tools/testing/selftests/vfio/Makefile | 2 | ||||
| -rw-r--r-- | tools/testing/selftests/vfio/lib/libvfio.mk | 2 |
9 files changed, 152 insertions, 51 deletions
diff --git a/Documentation/ABI/testing/debugfs-vfio b/Documentation/ABI/testing/debugfs-vfio index 70ec2d454686..ed2f29c3a9b4 100644 --- a/Documentation/ABI/testing/debugfs-vfio +++ b/Documentation/ABI/testing/debugfs-vfio @@ -29,3 +29,29 @@ Date: Oct 2025 KernelVersion: 6.18 Contact: Cédric Le Goater <clg@redhat.com> Description: Read the migration features of the vfio device. + +What: /sys/kernel/debug/vfio/<device>/pci +Date: June 2026 +KernelVersion: 7.2 +Contact: Alex Williamson <alex.williamson@nvidia.com> +Description: This debugfs file directory is used for debugging + VFIO PCI devices. + +What: /sys/kernel/debug/vfio/<device>/pci/nointxmask +Date: June 2026 +KernelVersion: 7.2 +Contact: Alex Williamson <alex.williamson@nvidia.com> +Description: Read the nointxmask policy latched for this device. This + policy governs whether the device may use PCI 2.3 style + INTx masking when supported, reporting a value of "N", or + requires APIC level INTx masking, reporting a value of "Y". + +What: /sys/kernel/debug/vfio/<device>/pci/disable_idle_d3 +Date: June 2026 +KernelVersion: 7.2 +Contact: Alex Williamson <alex.williamson@nvidia.com> +Description: Read the disable_idle_d3 policy latched for this device. This + policy governs whether the device PM runtime usage count is + kept elevated while the device is bound to the driver and + unused, reporting a value of "Y", or decremented to allow the + device to enter a low power state, reporting a value of "N". diff --git a/drivers/vfio/debugfs.c b/drivers/vfio/debugfs.c index 8b0ca7a09064..8a2f1b0cce3f 100644 --- a/drivers/vfio/debugfs.c +++ b/drivers/vfio/debugfs.c @@ -97,6 +97,7 @@ void vfio_device_debugfs_init(struct vfio_device *vdev) void vfio_device_debugfs_exit(struct vfio_device *vdev) { debugfs_remove_recursive(vdev->debug_root); + vdev->debug_root = NULL; } void vfio_debugfs_create_root(void) diff --git a/drivers/vfio/pci/mlx5/cmd.h b/drivers/vfio/pci/mlx5/cmd.h index deed0f132f39..c86d8b243a52 100644 --- a/drivers/vfio/pci/mlx5/cmd.h +++ b/drivers/vfio/pci/mlx5/cmd.h @@ -158,26 +158,29 @@ struct mlx5_vhca_qp { struct mlx5_vhca_page_tracker { u32 id; u32 pdn; - u8 is_err:1; - u8 object_changed:1; + /* Flags modified at runtime - dedicated storage unit */ + u8 is_err; + u8 object_changed; + int status; struct mlx5_uars_page *uar; struct mlx5_vhca_cq cq; struct mlx5_vhca_qp *host_qp; struct mlx5_vhca_qp *fw_qp; struct mlx5_nb nb; - int status; }; struct mlx5vf_pci_core_device { struct vfio_pci_core_device core_device; int vf_id; u16 vhca_id; + /* Flags only modified on setup/release - bitfield ok */ u8 migrate_cap:1; - u8 deferred_reset:1; - u8 mdev_detach:1; - u8 log_active:1; u8 chunk_mode:1; u8 mig_state_cap:1; + /* Flags modified at runtime - dedicated storage unit */ + u8 mdev_detach; + u8 log_active; + u8 deferred_reset; struct completion tracker_comp; /* protect migration state */ struct mutex state_mutex; diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 0c771064c0b8..830369ff878d 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -125,9 +125,30 @@ static int vfio_pci_open_device(struct vfio_device *core_vdev) return 0; } +static int vfio_pci_init_dev(struct vfio_device *core_vdev) +{ + struct vfio_pci_core_device *vdev = + container_of(core_vdev, struct vfio_pci_core_device, vdev); + + /* + * These behaviors originated in vfio-pci and moved into + * vfio-pci-core when the driver was split; vfio-pci remains the + * only driver that toggles them. Latch our module parameters per + * device at init time so that later parameter changes do not + * affect already-initialized devices. + */ + vdev->nointxmask = nointxmask; + vdev->disable_idle_d3 = disable_idle_d3; +#ifdef CONFIG_VFIO_PCI_VGA + vdev->disable_vga = disable_vga; +#endif + + return vfio_pci_core_init_dev(core_vdev); +} + static const struct vfio_device_ops vfio_pci_ops = { .name = "vfio-pci", - .init = vfio_pci_core_init_dev, + .init = vfio_pci_init_dev, .release = vfio_pci_core_release_dev, .open_device = vfio_pci_open_device, .close_device = vfio_pci_core_close_device, @@ -256,13 +277,6 @@ static void __init vfio_pci_fill_ids(void) static int __init vfio_pci_init(void) { int ret; - bool is_disable_vga = true; - -#ifdef CONFIG_VFIO_PCI_VGA - is_disable_vga = disable_vga; -#endif - - vfio_pci_core_set_params(nointxmask, is_disable_vga, disable_idle_d3); /* Register and scan for devices */ ret = pci_register_driver(&vfio_pci_driver); diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c index a28f1e99362c..3f11a9624b9c 100644 --- a/drivers/vfio/pci/vfio_pci_core.c +++ b/drivers/vfio/pci/vfio_pci_core.c @@ -11,6 +11,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/aperture.h> +#include <linux/debugfs.h> #include <linux/device.h> #include <linux/eventfd.h> #include <linux/file.h> @@ -29,6 +30,7 @@ #include <linux/sched/mm.h> #include <linux/iommufd.h> #include <linux/pci-p2pdma.h> +#include <linux/seq_file.h> #if IS_ENABLED(CONFIG_EEH) #include <asm/eeh.h> #endif @@ -38,10 +40,6 @@ #define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>" #define DRIVER_DESC "core driver for VFIO based PCI devices" -static bool nointxmask; -static bool disable_vga; -static bool disable_idle_d3; - static void vfio_pci_eventfd_rcu_free(struct rcu_head *rcu) { struct vfio_pci_eventfd *eventfd = @@ -92,15 +90,69 @@ struct vfio_pci_vf_token { int users; }; -static inline bool vfio_vga_disabled(void) +static inline bool vfio_vga_disabled(struct vfio_pci_core_device *vdev) { #ifdef CONFIG_VFIO_PCI_VGA - return disable_vga; + return vdev->disable_vga; #else return true; #endif } +#ifdef CONFIG_VFIO_DEBUGFS +static struct vfio_pci_core_device * +vfio_pci_core_debugfs_private(struct seq_file *seq) +{ + struct device *dev = seq->private; + struct vfio_device *core_vdev = container_of(dev, struct vfio_device, + device); + + return container_of(core_vdev, struct vfio_pci_core_device, vdev); +} + +static int vfio_pci_core_debugfs_nointxmask(struct seq_file *seq, void *data) +{ + struct vfio_pci_core_device *vdev = vfio_pci_core_debugfs_private(seq); + + seq_puts(seq, vdev->nointxmask ? "Y\n" : "N\n"); + return 0; +} + +static int vfio_pci_core_debugfs_disable_idle_d3(struct seq_file *seq, + void *data) +{ + struct vfio_pci_core_device *vdev = vfio_pci_core_debugfs_private(seq); + + seq_puts(seq, vdev->disable_idle_d3 ? "Y\n" : "N\n"); + return 0; +} + +/* + * disable_idle_d3 and nointxmask are writable module parameters latched + * per device at init, so a device's effective value can differ from the + * current parameter setting. Expose the per-device (read-only) values + * here for visibility; read-only parameters can't drift and are omitted. + */ +static void vfio_pci_core_debugfs_init(struct vfio_pci_core_device *vdev) +{ + struct device *dev = &vdev->vdev.device; + struct dentry *pci_dir; + + if (IS_ERR_OR_NULL(vdev->vdev.debug_root)) + return; + + pci_dir = debugfs_create_dir("pci", vdev->vdev.debug_root); + debugfs_create_devm_seqfile(dev, "nointxmask", pci_dir, + vfio_pci_core_debugfs_nointxmask); + debugfs_create_devm_seqfile(dev, "disable_idle_d3", pci_dir, + vfio_pci_core_debugfs_disable_idle_d3); +} +#else +static inline void vfio_pci_core_debugfs_init(struct vfio_pci_core_device *vdev) +{ +} +#endif /* CONFIG_VFIO_DEBUGFS */ + /* * Our VGA arbiter participation is limited since we don't know anything * about the device itself. However, if the device is the only VGA device @@ -111,11 +163,12 @@ static inline bool vfio_vga_disabled(void) */ static unsigned int vfio_pci_set_decode(struct pci_dev *pdev, bool single_vga) { + struct vfio_pci_core_device *vdev = dev_get_drvdata(&pdev->dev); struct pci_dev *tmp = NULL; unsigned char max_busnr; unsigned int decodes; - if (single_vga || !vfio_vga_disabled() || pci_is_root_bus(pdev->bus)) + if (single_vga || !vfio_vga_disabled(vdev) || pci_is_root_bus(pdev->bus)) return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM | VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; @@ -538,7 +591,7 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev) u16 cmd; u8 msix_pos; - if (!disable_idle_d3) { + if (!vdev->disable_idle_d3) { ret = pm_runtime_resume_and_get(&pdev->dev); if (ret < 0) return ret; @@ -562,7 +615,7 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev) if (!vdev->pci_saved_state) pci_dbg(pdev, "%s: Couldn't store saved state\n", __func__); - if (likely(!nointxmask)) { + if (likely(!vdev->nointxmask)) { if (vfio_pci_nointx(pdev)) { pci_info(pdev, "Masking broken INTx support\n"); vdev->nointx = true; @@ -602,7 +655,7 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev) vdev->has_dyn_msix = false; } - if (!vfio_vga_disabled() && vfio_pci_is_vga(pdev)) + if (!vfio_vga_disabled(vdev) && vfio_pci_is_vga(pdev)) vdev->has_vga = true; vfio_pci_core_map_bars(vdev); @@ -617,7 +670,7 @@ out_free_state: out_disable_device: pci_disable_device(pdev); out_power: - if (!disable_idle_d3) + if (!vdev->disable_idle_d3) pm_runtime_put(&pdev->dev); return ret; } @@ -753,7 +806,7 @@ out: vfio_pci_dev_set_try_reset(vdev->vdev.dev_set); /* Put the pm-runtime usage counter acquired during enable */ - if (!disable_idle_d3) + if (!vdev->disable_idle_d3) pm_runtime_put(&pdev->dev); } EXPORT_SYMBOL_GPL(vfio_pci_core_disable); @@ -2239,19 +2292,23 @@ int vfio_pci_core_register_device(struct vfio_pci_core_device *vdev) dev->driver->pm = &vfio_pci_core_pm_ops; pm_runtime_allow(dev); - if (!disable_idle_d3) + if (!vdev->disable_idle_d3) pm_runtime_put(dev); ret = vfio_register_group_dev(&vdev->vdev); if (ret) goto out_power; + + vfio_pci_core_debugfs_init(vdev); + return 0; out_power: - if (!disable_idle_d3) + if (!vdev->disable_idle_d3) pm_runtime_get_noresume(dev); pm_runtime_forbid(dev); + vfio_pci_vga_uninit(vdev); out_vf: vfio_pci_vf_uninit(vdev); return ret; @@ -2267,7 +2324,7 @@ void vfio_pci_core_unregister_device(struct vfio_pci_core_device *vdev) vfio_pci_vf_uninit(vdev); vfio_pci_vga_uninit(vdev); - if (!disable_idle_d3) + if (!vdev->disable_idle_d3) pm_runtime_get_noresume(&vdev->pdev->dev); pm_runtime_forbid(&vdev->pdev->dev); @@ -2599,7 +2656,7 @@ static void vfio_pci_dev_set_try_reset(struct vfio_device_set *dev_set) * state. Increment the usage count for all the devices in the dev_set * before reset and decrement the same after reset. */ - if (!disable_idle_d3 && vfio_pci_dev_set_pm_runtime_get(dev_set)) + if (vfio_pci_dev_set_pm_runtime_get(dev_set)) return; if (!pci_reset_bus(pdev)) @@ -2609,20 +2666,10 @@ static void vfio_pci_dev_set_try_reset(struct vfio_device_set *dev_set) if (reset_done) cur->needs_reset = false; - if (!disable_idle_d3) - pm_runtime_put(&cur->pdev->dev); + pm_runtime_put(&cur->pdev->dev); } } -void vfio_pci_core_set_params(bool is_nointxmask, bool is_disable_vga, - bool is_disable_idle_d3) -{ - nointxmask = is_nointxmask; - disable_vga = is_disable_vga; - disable_idle_d3 = is_disable_idle_d3; -} -EXPORT_SYMBOL_GPL(vfio_pci_core_set_params); - static void vfio_pci_core_cleanup(void) { vfio_pci_uninit_perm_bits(); diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c index 5e0422014523..ed538aebb0b8 100644 --- a/drivers/vfio/vfio_main.c +++ b/drivers/vfio/vfio_main.c @@ -407,6 +407,13 @@ void vfio_unregister_group_dev(struct vfio_device *device) vfio_device_group_unregister(device); /* + * Remove debugfs before device_del(), which releases devres. Some + * debugfs entries are created with debugfs_create_devm_seqfile() and + * therefore rely on devres-managed inode private data. + */ + vfio_device_debugfs_exit(device); + + /* * Balances vfio_device_add() in register path, also prevents * new device opened by userspace in the cdev path. */ @@ -435,7 +442,6 @@ void vfio_unregister_group_dev(struct vfio_device *device) } } - vfio_device_debugfs_exit(device); /* Balances vfio_device_set_group in register path */ vfio_device_remove_group(device); } diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h index 5fc6ce4dd786..9a1674c152aa 100644 --- a/include/linux/vfio_pci_core.h +++ b/include/linux/vfio_pci_core.h @@ -101,6 +101,9 @@ struct vfio_pci_core_device { const struct vfio_pci_device_ops *pci_ops; void __iomem *barmap[PCI_STD_NUM_BARS]; bool bar_mmap_supported[PCI_STD_NUM_BARS]; + /* Flags modified at runtime - dedicated storage unit */ + bool virq_disabled; + bool bardirty; u8 *pci_config_map; u8 *vconfig; struct perm_bits *msi_perm; @@ -115,18 +118,21 @@ struct vfio_pci_core_device { u16 msix_size; u32 msix_offset; u32 rbar[7]; + /* Flags only modified on setup/release - bitfield ok */ bool has_dyn_msix:1; bool pci_2_3:1; - bool virq_disabled:1; bool reset_works:1; bool extended_caps:1; - bool bardirty:1; bool has_vga:1; - bool needs_reset:1; bool nointx:1; bool needs_pm_restore:1; - bool pm_intx_masked:1; - bool pm_runtime_engaged:1; + bool disable_idle_d3:1; + bool nointxmask:1; + bool disable_vga:1; + /* Flags modified at runtime - dedicated storage unit */ + bool needs_reset; + bool pm_intx_masked; + bool pm_runtime_engaged; bool sriov_active; struct pci_saved_state *pci_saved_state; struct pci_saved_state *pm_save; @@ -157,8 +163,6 @@ int vfio_pci_core_register_dev_region(struct vfio_pci_core_device *vdev, unsigned int type, unsigned int subtype, const struct vfio_pci_regops *ops, size_t size, u32 flags, void *data); -void vfio_pci_core_set_params(bool nointxmask, bool is_disable_vga, - bool is_disable_idle_d3); void vfio_pci_core_close_device(struct vfio_device *core_vdev); int vfio_pci_core_init_dev(struct vfio_device *core_vdev); void vfio_pci_core_release_dev(struct vfio_device *core_vdev); diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile index e6e8cb52ab03..2c32c48db509 100644 --- a/tools/testing/selftests/vfio/Makefile +++ b/tools/testing/selftests/vfio/Makefile @@ -29,8 +29,6 @@ CFLAGS += $(EXTRA_CFLAGS) LDFLAGS += -pthread -LDLIBS += -luuid - $(TEST_GEN_PROGS): $(OUTPUT)/%: $(OUTPUT)/%.o $(LIBVFIO_O) $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $< $(LIBVFIO_O) $(LDLIBS) -o $@ diff --git a/tools/testing/selftests/vfio/lib/libvfio.mk b/tools/testing/selftests/vfio/lib/libvfio.mk index 2b8d73b7d329..67942b085068 100644 --- a/tools/testing/selftests/vfio/lib/libvfio.mk +++ b/tools/testing/selftests/vfio/lib/libvfio.mk @@ -26,6 +26,8 @@ $(LIBVFIO_O_DIRS): CFLAGS += -I$(LIBVFIO_SRCDIR)/include +LDLIBS += -luuid + $(LIBVFIO_O): $(LIBVFIO_OUTPUT)/%.o : $(LIBVFIO_SRCDIR)/%.c | $(LIBVFIO_O_DIRS) $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ |
