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 <mario.limonciello@dell.com>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Yehezkel Bernat <yehezkel.bernat@intel.com>
Signed-off-by: Darren Hart (VMware) <dvhart@infradead.org>
[andy fixed merge conflicts and bump kernel version for ABI]
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
This commit is contained in:
Mario Limonciello 2017-09-08 10:23:11 -05:00 committed by Andy Shevchenko
parent 2bd6bf03f4
commit ce6a90027c
6 changed files with 146 additions and 0 deletions

View File

@ -0,0 +1,11 @@
What: /sys/devices/platform/<platform>/force_power
Date: September 2017
KernelVersion: 4.15
Contact: "Mario Limonciello" <mario.limonciello@dell.com>
Description:
Modify the platform force power state, influencing
Thunderbolt controllers to turn on or off when no
devices are connected (write-only)
There are two available states:
* 0 -> Force power disabled
* 1 -> Force power enabled

View File

@ -197,3 +197,18 @@ information is missing.
To recover from this mode, one needs to flash a valid NVM image to the
host host controller in the same way it is done in the previous chapter.
Forcing power
-------------
Many OEMs include a method that can be used to force the power of a
thunderbolt controller to an "On" state even if nothing is connected.
If supported by your machine this will be exposed by the WMI bus with
a sysfs attribute called "force_power".
For example the intel-wmi-thunderbolt driver exposes this attribute in:
/sys/devices/platform/PNP0C14:00/wmi_bus/wmi_bus-PNP0C14:00/86CCFD48-205E-4A77-9C48-2021CBEDE341/force_power
To force the power to on, write 1 to this attribute file.
To disable force power, write 0 to this attribute file.
Note: it's currently not possible to query the force power state of a platform.

View File

@ -7092,6 +7092,11 @@ F: Documentation/wimax/README.i2400m
F: drivers/net/wimax/i2400m/
F: include/uapi/linux/wimax/i2400m.h
INTEL WMI THUNDERBOLT FORCE POWER DRIVER
M: Mario Limonciello <mario.limonciello@dell.com>
S: Maintained
F: drivers/platform/x86/intel-wmi-thunderbolt.c
INTEL(R) TRACE HUB
M: Alexander Shishkin <alexander.shishkin@linux.intel.com>
S: Supported

View File

@ -658,6 +658,19 @@ config WMI_BMOF
To compile this driver as a module, choose M here: the module will
be called wmi-bmof.
config INTEL_WMI_THUNDERBOLT
tristate "Intel WMI thunderbolt force power driver"
depends on ACPI_WMI
default ACPI_WMI
---help---
Say Y here if you want to be able to use the WMI interface on select
systems to force the power control of Intel Thunderbolt controllers.
This is useful for updating the firmware when devices are not plugged
into the controller.
To compile this driver as a module, choose M here: the module will
be called intel-wmi-thunderbolt.
config MSI_WMI
tristate "MSI WMI extras"
depends on ACPI_WMI

View File

@ -39,6 +39,7 @@ obj-$(CONFIG_PEAQ_WMI) += peaq-wmi.o
obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o
obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
obj-$(CONFIG_WMI_BMOF) += wmi-bmof.o
obj-$(CONFIG_INTEL_WMI_THUNDERBOLT) += intel-wmi-thunderbolt.o
# toshiba_acpi must link after wmi to ensure that wmi devices are found
# before toshiba_acpi initializes

View File

@ -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 <linux/acpi.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/types.h>
#include <linux/wmi.h>
#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 <mario.limonciello@dell.com>");
MODULE_DESCRIPTION("Intel WMI Thunderbolt force power driver");
MODULE_LICENSE("GPL");