From ce6a90027c10f970f872de5db0294f9e3e969f1c Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 8 Sep 2017 10:23:11 -0500 Subject: platform/x86: Add driver to force WMI Thunderbolt controller power status Current implementations of Intel Thunderbolt controllers will go into a low power mode when not in use. Many machines containing these controllers also have a GPIO wired up that can force the controller awake. This is offered via a ACPI-WMI interface intended to be manipulated by a userspace utility. This mechanism is provided by Intel to OEMs to include in BIOS. It uses an industry wide GUID that is populated in a separate _WDG entry with no binary MOF. This interface allows software such as fwupd to wake up thunderbolt controllers to query the firmware version or flash new firmware. Signed-off-by: Mario Limonciello Reviewed-by: Mika Westerberg Reviewed-by: Yehezkel Bernat Signed-off-by: Darren Hart (VMware) [andy fixed merge conflicts and bump kernel version for ABI] Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel-wmi-thunderbolt.c | 101 +++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 drivers/platform/x86/intel-wmi-thunderbolt.c (limited to 'drivers/platform/x86/intel-wmi-thunderbolt.c') diff --git a/drivers/platform/x86/intel-wmi-thunderbolt.c b/drivers/platform/x86/intel-wmi-thunderbolt.c new file mode 100644 index 000000000000..32fb6cc33d72 --- /dev/null +++ b/drivers/platform/x86/intel-wmi-thunderbolt.c @@ -0,0 +1,101 @@ +/* + * WMI Thunderbolt driver + * + * Copyright (C) 2017 Dell Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define INTEL_WMI_THUNDERBOLT_GUID "86CCFD48-205E-4A77-9C48-2021CBEDE341" + +static ssize_t force_power_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct acpi_buffer input; + acpi_status status; + u8 mode; + + input.length = sizeof(u8); + input.pointer = &mode; + mode = hex_to_bin(buf[0]); + if (mode == 0 || mode == 1) { + status = wmi_evaluate_method(INTEL_WMI_THUNDERBOLT_GUID, 0, 1, + &input, NULL); + if (ACPI_FAILURE(status)) { + pr_err("intel-wmi-thunderbolt: failed setting %s\n", + buf); + return -ENODEV; + } + } else { + pr_err("intel-wmi-thunderbolt: unsupported mode: %d", mode); + } + return count; +} + +static DEVICE_ATTR_WO(force_power); + +static struct attribute *tbt_attrs[] = { + &dev_attr_force_power.attr, + NULL +}; + +static const struct attribute_group tbt_attribute_group = { + .attrs = tbt_attrs, +}; + +static int intel_wmi_thunderbolt_probe(struct wmi_device *wdev) +{ + int ret; + + ret = sysfs_create_group(&wdev->dev.kobj, &tbt_attribute_group); + kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE); + return ret; +} + +static int intel_wmi_thunderbolt_remove(struct wmi_device *wdev) +{ + sysfs_remove_group(&wdev->dev.kobj, &tbt_attribute_group); + kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE); + return 0; +} + +static const struct wmi_device_id intel_wmi_thunderbolt_id_table[] = { + { .guid_string = INTEL_WMI_THUNDERBOLT_GUID }, + { }, +}; + +static struct wmi_driver intel_wmi_thunderbolt_driver = { + .driver = { + .name = "intel-wmi-thunderbolt", + }, + .probe = intel_wmi_thunderbolt_probe, + .remove = intel_wmi_thunderbolt_remove, + .id_table = intel_wmi_thunderbolt_id_table, +}; + +module_wmi_driver(intel_wmi_thunderbolt_driver); + +MODULE_ALIAS("wmi:" INTEL_WMI_THUNDERBOLT_GUID); +MODULE_AUTHOR("Mario Limonciello "); +MODULE_DESCRIPTION("Intel WMI Thunderbolt force power driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 12933ea2b8c1e1f87a5dfece947325ee9e6d65b0 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 14 Sep 2017 01:41:55 -0500 Subject: platform/x86: intel-wmi-thunderbolt: Silence error cases These were raised by Lukas Wunner as potential DOS attacks against the system log by passing bad data to sysfs. Signed-off-by: Mario Limonciello Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/intel-wmi-thunderbolt.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/platform/x86/intel-wmi-thunderbolt.c') diff --git a/drivers/platform/x86/intel-wmi-thunderbolt.c b/drivers/platform/x86/intel-wmi-thunderbolt.c index 32fb6cc33d72..c2257bd06f18 100644 --- a/drivers/platform/x86/intel-wmi-thunderbolt.c +++ b/drivers/platform/x86/intel-wmi-thunderbolt.c @@ -41,13 +41,10 @@ static ssize_t force_power_store(struct device *dev, if (mode == 0 || mode == 1) { status = wmi_evaluate_method(INTEL_WMI_THUNDERBOLT_GUID, 0, 1, &input, NULL); - if (ACPI_FAILURE(status)) { - pr_err("intel-wmi-thunderbolt: failed setting %s\n", - buf); + if (ACPI_FAILURE(status)) return -ENODEV; - } } else { - pr_err("intel-wmi-thunderbolt: unsupported mode: %d", mode); + return -EINVAL; } return count; } -- cgit v1.2.3