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

vfio: platform: call _RST method when using ACPI

The device tree code checks for the presence of a reset driver and calls
the of_reset function pointer by looking up the reset driver as a module.

ACPI defines _RST method to perform device level reset. After the _RST
method is executed, the OS can resume using the device. _RST method is
expected to stop DMA transfers and IRQs.

This patch introduces two functions as vfio_platform_acpi_has_reset and
vfio_platform_acpi_call_reset. The has reset method is used to declare
reset capability via the ioctl flag VFIO_DEVICE_FLAGS_RESET. The call
reset function is used to execute the _RST ACPI method.

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
d30daa33 5afec274

+49 -1
+49 -1
drivers/vfio/platform/vfio_platform_common.c
··· 28 28 #define DRIVER_AUTHOR "Antonios Motakis <a.motakis@virtualopensystems.com>" 29 29 #define DRIVER_DESC "VFIO platform base module" 30 30 31 + #define VFIO_PLATFORM_IS_ACPI(vdev) ((vdev)->acpihid != NULL) 32 + 31 33 static LIST_HEAD(reset_list); 32 34 static DEFINE_MUTEX(driver_lock); 33 35 ··· 73 71 return WARN_ON(!vdev->acpihid) ? -EINVAL : 0; 74 72 } 75 73 74 + int vfio_platform_acpi_call_reset(struct vfio_platform_device *vdev, 75 + const char **extra_dbg) 76 + { 77 + #ifdef CONFIG_ACPI 78 + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 79 + struct device *dev = vdev->device; 80 + acpi_handle handle = ACPI_HANDLE(dev); 81 + acpi_status acpi_ret; 82 + 83 + acpi_ret = acpi_evaluate_object(handle, "_RST", NULL, &buffer); 84 + if (ACPI_FAILURE(acpi_ret)) { 85 + if (extra_dbg) 86 + *extra_dbg = acpi_format_exception(acpi_ret); 87 + return -EINVAL; 88 + } 89 + 90 + return 0; 91 + #else 92 + return -ENOENT; 93 + #endif 94 + } 95 + 96 + bool vfio_platform_acpi_has_reset(struct vfio_platform_device *vdev) 97 + { 98 + #ifdef CONFIG_ACPI 99 + struct device *dev = vdev->device; 100 + acpi_handle handle = ACPI_HANDLE(dev); 101 + 102 + return acpi_has_method(handle, "_RST"); 103 + #else 104 + return false; 105 + #endif 106 + } 107 + 76 108 static bool vfio_platform_has_reset(struct vfio_platform_device *vdev) 77 109 { 110 + if (VFIO_PLATFORM_IS_ACPI(vdev)) 111 + return vfio_platform_acpi_has_reset(vdev); 112 + 78 113 return vdev->of_reset ? true : false; 79 114 } 80 115 81 116 static void vfio_platform_get_reset(struct vfio_platform_device *vdev) 82 117 { 118 + if (VFIO_PLATFORM_IS_ACPI(vdev)) 119 + return; 120 + 83 121 vdev->of_reset = vfio_platform_lookup_reset(vdev->compat, 84 122 &vdev->reset_module); 85 123 if (!vdev->of_reset) { ··· 131 89 132 90 static void vfio_platform_put_reset(struct vfio_platform_device *vdev) 133 91 { 92 + if (VFIO_PLATFORM_IS_ACPI(vdev)) 93 + return; 94 + 134 95 if (vdev->of_reset) 135 96 module_put(vdev->reset_module); 136 97 } ··· 209 164 static int vfio_platform_call_reset(struct vfio_platform_device *vdev, 210 165 const char **extra_dbg) 211 166 { 212 - if (vdev->of_reset) { 167 + if (VFIO_PLATFORM_IS_ACPI(vdev)) { 168 + dev_info(vdev->device, "reset\n"); 169 + return vfio_platform_acpi_call_reset(vdev, extra_dbg); 170 + } else if (vdev->of_reset) { 213 171 dev_info(vdev->device, "reset\n"); 214 172 return vdev->of_reset(vdev); 215 173 }