Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vfio, platform: make reset driver a requirement by default

The code was allowing platform devices to be used without a supporting
VFIO reset driver. The hardware can be left in some inconsistent state
after a guest machine abort.

The reset driver will put the hardware back to safe state and disable
interrupts before returning the control back to the host machine.

Adding a new reset_required kernel module option to platform VFIO drivers.
The default value is true for the DT and ACPI based drivers.
The reset requirement value for AMBA drivers is set to false and is
unchangeable to maintain the existing functionality.

New requirements are:
1. A reset function needs to be implemented by the corresponding driver
via DT/ACPI.
2. The reset function needs to be discovered via DT/ACPI.

The probe of the driver will fail if any of the above conditions are
not satisfied.

Signed-off-by: Sinan Kaya <okaya@codeaurora.org>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>

authored by

Sinan Kaya and committed by
Alex Williamson
b5add544 d30daa33

+19 -4
+1
drivers/vfio/platform/vfio_amba.c
··· 68 68 vdev->get_resource = get_amba_resource; 69 69 vdev->get_irq = get_amba_irq; 70 70 vdev->parent_module = THIS_MODULE; 71 + vdev->reset_required = false; 71 72 72 73 ret = vfio_platform_probe_common(vdev, &adev->dev); 73 74 if (ret) {
+5
drivers/vfio/platform/vfio_platform.c
··· 23 23 #define DRIVER_AUTHOR "Antonios Motakis <a.motakis@virtualopensystems.com>" 24 24 #define DRIVER_DESC "VFIO for platform devices - User Level meta-driver" 25 25 26 + static bool reset_required = true; 27 + module_param(reset_required, bool, 0444); 28 + MODULE_PARM_DESC(reset_required, "override reset requirement (default: 1)"); 29 + 26 30 /* probing devices from the linux platform bus */ 27 31 28 32 static struct resource *get_platform_resource(struct vfio_platform_device *vdev, ··· 70 66 vdev->get_resource = get_platform_resource; 71 67 vdev->get_irq = get_platform_irq; 72 68 vdev->parent_module = THIS_MODULE; 69 + vdev->reset_required = reset_required; 73 70 74 71 ret = vfio_platform_probe_common(vdev, &pdev->dev); 75 72 if (ret)
+11 -4
drivers/vfio/platform/vfio_platform_common.c
··· 115 115 return vdev->of_reset ? true : false; 116 116 } 117 117 118 - static void vfio_platform_get_reset(struct vfio_platform_device *vdev) 118 + static int vfio_platform_get_reset(struct vfio_platform_device *vdev) 119 119 { 120 120 if (VFIO_PLATFORM_IS_ACPI(vdev)) 121 - return; 121 + return vfio_platform_acpi_has_reset(vdev) ? 0 : -ENOENT; 122 122 123 123 vdev->of_reset = vfio_platform_lookup_reset(vdev->compat, 124 124 &vdev->reset_module); ··· 127 127 vdev->of_reset = vfio_platform_lookup_reset(vdev->compat, 128 128 &vdev->reset_module); 129 129 } 130 + 131 + return vdev->of_reset ? 0 : -ENOENT; 130 132 } 131 133 132 134 static void vfio_platform_put_reset(struct vfio_platform_device *vdev) ··· 669 667 670 668 vdev->device = dev; 671 669 670 + ret = vfio_platform_get_reset(vdev); 671 + if (ret && vdev->reset_required) { 672 + pr_err("vfio: no reset function found for device %s\n", 673 + vdev->name); 674 + return ret; 675 + } 676 + 672 677 group = vfio_iommu_group_get(dev); 673 678 if (!group) { 674 679 pr_err("VFIO: No IOMMU group for device %s\n", vdev->name); ··· 687 678 vfio_iommu_group_put(group, dev); 688 679 return ret; 689 680 } 690 - 691 - vfio_platform_get_reset(vdev); 692 681 693 682 mutex_init(&vdev->igate); 694 683
+2
drivers/vfio/platform/vfio_platform_private.h
··· 73 73 (*get_resource)(struct vfio_platform_device *vdev, int i); 74 74 int (*get_irq)(struct vfio_platform_device *vdev, int i); 75 75 int (*of_reset)(struct vfio_platform_device *vdev); 76 + 77 + bool reset_required; 76 78 }; 77 79 78 80 typedef int (*vfio_platform_reset_fn_t)(struct vfio_platform_device *vdev);