summaryrefslogtreecommitdiff
path: root/drivers/platform/x86
diff options
context:
space:
mode:
authorArmin Wolf <W_Armin@gmx.de>2024-10-05 23:38:25 +0200
committerIlpo Järvinen <ilpo.jarvinen@linux.intel.com>2024-10-09 12:04:48 +0300
commitd12586e1072d92070783c854819a0ca8c82c5439 (patch)
tree5e269c19be1b5049fdb965d482e773c63abffcbf /drivers/platform/x86
parent066c779b094b63754e0742ad8675d72d6c0a46f6 (diff)
platform/x86: wmi: Implement proper shutdown handling
When performing a system shutdown under Windows, all WMI clients are terminated. This means that the ACPI BIOS might expect all WMI devices to be disabled when shutting down. Emulate this behaviour by disabling all active WMI devices during shutdown. Also introduce a new WMI driver callback to allow WMI drivers to perform any device-specific actions before disabling the WMI device. Tested on a Dell Inspiron 3505. Signed-off-by: Armin Wolf <W_Armin@gmx.de> Link: https://lore.kernel.org/r/20241005213825.701887-2-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Diffstat (limited to 'drivers/platform/x86')
-rw-r--r--drivers/platform/x86/wmi.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index 3cbe180c3fc0..a01223c23d10 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -884,6 +884,32 @@ static void wmi_dev_remove(struct device *dev)
dev_warn(dev, "failed to disable device\n");
}
+static void wmi_dev_shutdown(struct device *dev)
+{
+ struct wmi_driver *wdriver;
+ struct wmi_block *wblock;
+
+ if (dev->driver) {
+ wdriver = drv_to_wdrv(dev->driver);
+ wblock = dev_to_wblock(dev);
+
+ /*
+ * Some machines return bogus WMI event data when disabling
+ * the WMI event. Because of this we must prevent the associated
+ * WMI driver from receiving new WMI events before disabling it.
+ */
+ down_write(&wblock->notify_lock);
+ wblock->driver_ready = false;
+ up_write(&wblock->notify_lock);
+
+ if (wdriver->shutdown)
+ wdriver->shutdown(to_wmi_device(dev));
+
+ if (ACPI_FAILURE(wmi_method_enable(wblock, false)))
+ dev_warn(dev, "Failed to disable device\n");
+ }
+}
+
static struct class wmi_bus_class = {
.name = "wmi_bus",
};
@@ -895,6 +921,7 @@ static const struct bus_type wmi_bus_type = {
.uevent = wmi_dev_uevent,
.probe = wmi_dev_probe,
.remove = wmi_dev_remove,
+ .shutdown = wmi_dev_shutdown,
};
static const struct device_type wmi_type_event = {