aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-11-18 13:26:57 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-11-18 13:26:57 -0500
commit07c455ee222f3ad219c2835d05a175a326a138fb (patch)
treec3fdcd89a4fe87877963162de8bc428bb265bb8e
parent1deab8ce2c91e3b16563b7a7ea150f82334262ec (diff)
parentaaa40965d2342137d756121993c395e2a7463a8d (diff)
Merge tag 'platform-drivers-x86-v4.15-1' of git://git.infradead.org/linux-platform-drivers-x86
Pull x86 platform driver updates from Andy Shevchenko: "Here is the collected material against Platform Drivers x86 subsystem. It's rather bit busy cycle for PDx86, mostly due to Dell SMBIOS driver activity For this cycle we have quite an update for the Dell SMBIOS driver including WMI work to provide an interface for SMBIOS tokens via sysfs and WMI support for 2017+ Dell laptop models. SMM dispatcher code is split into a separate driver followed by a new WMI dispatcher. The latter provides a character device interface to user space. The git history also contains a merge of immutable branch from Wolfram Sang in order to apply a dependent fix to the Intel CherryTrail Battery Management driver. Other Intel drivers got a lot of cleanups. The Turbo Boost Max 3.0 support is added for Intel Skylake. Peaq WMI hotkeys driver gets its own maintainer and white list of supported models. Silead DMI is expanded to support few additional platforms. Tablet mode via GMMS ACPI method is added to support some ThinkPad tablets. new driver: - Add driver to force WMI Thunderbolt controller power status asus-wmi: - Add lightbar led support dell-laptop: - Allocate buffer before rfkill use dell-smbios: - fix string overflow - Add filtering support - Introduce dispatcher for SMM calls - Add a sysfs interface for SMBIOS tokens - only run if proper oem string is detected - Prefix class/select with cmd_ - Add pr_fmt definition to driver dell-smbios-smm: - test for WSMT dell-smbios-wmi: - release mutex lock on WMI call failure - introduce userspace interface - Add new WMI dispatcher driver dell-smo8800: - remove redundant assignments to byte_data dell-wmi: - don't check length returned - clean up wmi descriptor check - increase severity of some failures - Do not match on descriptor GUID modalias - Label driver as handling notifications dell-*wmi*: - Relay failed initial probe to dependent drivers dell-wmi-descriptor: - check if memory was allocated - split WMI descriptor into it's own driver fujitsu-laptop: - Fix radio LED detection - Don't oops when FUJ02E3 is not presnt hp_accel: - Add quirk for HP ProBook 440 G4 hp-wmi: - Fix tablet mode detection for convertibles ideapad-laptop: - Add Lenovo Yoga 920-13IKB to no_hw_rfkill dmi list intel_cht_int33fe: - Update fusb302 type string, add properties - make a couple of local functions static - Work around BIOS bug on some devices intel-hid: - Power button suspend on Dell Latitude 7275 intel_ips: - Convert timers to use timer_setup() - Remove FSF address from GPL notice - Remove unneeded fields and label - Keep pointer to struct device - Use PCI_VDEVICE() macro - Switch to new PCI IRQ allocation API - Simplify error handling via devres API intel_pmc_ipc: - Revert Use MFD framework to create dependent devices - Use MFD framework to create dependent devices - Use spin_lock to protect GCR updates - Use devm_* calls in driver probe function intel_punit_ipc: - Fix resource ioremap warning intel_telemetry: - Remove useless default in Kconfig - Add needed inclusion - cleanup redundant headers - Fix typos - Fix load failure info intel_telemetry_debugfs: - Use standard ARRAY_SIZE() macro intel_turbo_max_3: - Add Skylake platform intel-wmi-thunderbolt: - Silence error cases mlx-platform: - make a couple of structures static peaq_wmi: - Fix missing terminating entry for peaq_dmi_table peaq-wmi: - Remove unnecessary checks from peaq_wmi_exit - Add DMI check before binding to the WMI interface - Revert Blacklist Lenovo ideapad 700-15ISK - Blacklist Lenovo ideapad 700-15ISK silead_dmi: - Add silead, home-button property to some tablets - Add entry for the Digma e200 tablet - Fix GP-electronic T701 entry - Add entry for the Chuwi Hi8 Pro tablet sony-laptop: - Drop variable assignment in sony_nc_setup_rfkill() - Fix error handling in sony_nc_setup_rfkill() thinkpad_acpi: - Implement tablet mode using GMMS method tools/wmi: - add a sample for dell smbios communication over WMI wmi: - release mutex on module acquistion failure - create userspace interface for drivers - Don't allow drivers to get each other's GUIDs - Add new method wmidev_evaluate_method - Destroy on cleanup rather than unregister - Cleanup exit routine in reverse order of init - Sort include list" * tag 'platform-drivers-x86-v4.15-1' of git://git.infradead.org/linux-platform-drivers-x86: (74 commits) platform/x86: silead_dmi: Add silead, home-button property to some tablets platform/x86: dell-laptop: Allocate buffer before rfkill use platform/x86: dell-*wmi*: Relay failed initial probe to dependent drivers platform/x86: dell-wmi-descriptor: check if memory was allocated platform/x86: Revert intel_pmc_ipc: Use MFD framework to create dependent devices platform/x86: dell-smbios-wmi: release mutex lock on WMI call failure platform/x86: wmi: release mutex on module acquistion failure platform/x86: dell-smbios: fix string overflow platform/x86: intel_pmc_ipc: Use MFD framework to create dependent devices platform/x86: intel_punit_ipc: Fix resource ioremap warning platform/x86: dell-smo8800: remove redundant assignments to byte_data platform/x86: hp-wmi: Fix tablet mode detection for convertibles platform/x86: intel_ips: Convert timers to use timer_setup() platform/x86: sony-laptop: Drop variable assignment in sony_nc_setup_rfkill() platform/x86: sony-laptop: Fix error handling in sony_nc_setup_rfkill() tools/wmi: add a sample for dell smbios communication over WMI platform/x86: dell-smbios-wmi: introduce userspace interface platform/x86: wmi: create userspace interface for drivers platform/x86: dell-smbios: Add filtering support platform/x86: dell-smbios-smm: test for WSMT ...
-rw-r--r--Documentation/ABI/testing/dell-smbios-wmi41
-rw-r--r--Documentation/ABI/testing/sysfs-platform-dell-smbios21
-rw-r--r--Documentation/ABI/testing/sysfs-platform-intel-wmi-thunderbolt11
-rw-r--r--Documentation/admin-guide/thunderbolt.rst15
-rw-r--r--MAINTAINERS39
-rw-r--r--drivers/platform/x86/Kconfig56
-rw-r--r--drivers/platform/x86/Makefile4
-rw-r--r--drivers/platform/x86/asus-wmi.c63
-rw-r--r--drivers/platform/x86/dell-laptop.c284
-rw-r--r--drivers/platform/x86/dell-smbios-smm.c196
-rw-r--r--drivers/platform/x86/dell-smbios-wmi.c272
-rw-r--r--drivers/platform/x86/dell-smbios.c512
-rw-r--r--drivers/platform/x86/dell-smbios.h49
-rw-r--r--drivers/platform/x86/dell-smo8800.c3
-rw-r--r--drivers/platform/x86/dell-wmi-descriptor.c191
-rw-r--r--drivers/platform/x86/dell-wmi-descriptor.h27
-rw-r--r--drivers/platform/x86/dell-wmi.c97
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c14
-rw-r--r--drivers/platform/x86/hp-wmi.c2
-rw-r--r--drivers/platform/x86/hp_accel.c1
-rw-r--r--drivers/platform/x86/ideapad-laptop.c7
-rw-r--r--drivers/platform/x86/intel-hid.c18
-rw-r--r--drivers/platform/x86/intel-wmi-thunderbolt.c98
-rw-r--r--drivers/platform/x86/intel_cht_int33fe.c114
-rw-r--r--drivers/platform/x86/intel_ips.c160
-rw-r--r--drivers/platform/x86/intel_ips.h4
-rw-r--r--drivers/platform/x86/intel_punit_ipc.c8
-rw-r--r--drivers/platform/x86/intel_telemetry_core.c3
-rw-r--r--drivers/platform/x86/intel_telemetry_debugfs.c24
-rw-r--r--drivers/platform/x86/intel_telemetry_pltdrv.c25
-rw-r--r--drivers/platform/x86/intel_turbo_max_3.c1
-rw-r--r--drivers/platform/x86/mlx-platform.c4
-rw-r--r--drivers/platform/x86/peaq-wmi.c19
-rw-r--r--drivers/platform/x86/silead_dmi.c52
-rw-r--r--drivers/platform/x86/sony-laptop.c16
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c132
-rw-r--r--drivers/platform/x86/wmi.c254
-rw-r--r--include/linux/wmi.h13
-rw-r--r--include/uapi/linux/wmi.h73
-rw-r--r--tools/Makefile14
-rw-r--r--tools/wmi/Makefile18
-rw-r--r--tools/wmi/dell-smbios-example.c210
42 files changed, 2613 insertions, 552 deletions
diff --git a/Documentation/ABI/testing/dell-smbios-wmi b/Documentation/ABI/testing/dell-smbios-wmi
new file mode 100644
index 000000000000..fc919ce16008
--- /dev/null
+++ b/Documentation/ABI/testing/dell-smbios-wmi
@@ -0,0 +1,41 @@
1What: /dev/wmi/dell-smbios
2Date: November 2017
3KernelVersion: 4.15
4Contact: "Mario Limonciello" <mario.limonciello@dell.com>
5Description:
6 Perform SMBIOS calls on supported Dell machines.
7 through the Dell ACPI-WMI interface.
8
9 IOCTL's and buffer formats are defined in:
10 <uapi/linux/wmi.h>
11
12 1) To perform an SMBIOS call from userspace, you'll need to
13 first determine the minimum size of the calling interface
14 buffer for your machine.
15 Platforms that contain larger buffers can return larger
16 objects from the system firmware.
17 Commonly this size is either 4k or 32k.
18
19 To determine the size of the buffer read() a u64 dword from
20 the WMI character device /dev/wmi/dell-smbios.
21
22 2) After you've determined the minimum size of the calling
23 interface buffer, you can allocate a structure that represents
24 the structure documented above.
25
26 3) In the 'length' object store the size of the buffer you
27 determined above and allocated.
28
29 4) In this buffer object, prepare as necessary for the SMBIOS
30 call you're interested in. Typically SMBIOS buffers have
31 "class", "select", and "input" defined to values that coincide
32 with the data you are interested in.
33 Documenting class/select/input values is outside of the scope
34 of this documentation. Check with the libsmbios project for
35 further documentation on these values.
36
37 6) Run the call by using ioctl() as described in the header.
38
39 7) The output will be returned in the buffer object.
40
41 8) Be sure to free up your allocated object.
diff --git a/Documentation/ABI/testing/sysfs-platform-dell-smbios b/Documentation/ABI/testing/sysfs-platform-dell-smbios
new file mode 100644
index 000000000000..205d3b6361e0
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-dell-smbios
@@ -0,0 +1,21 @@
1What: /sys/devices/platform/<platform>/tokens/*
2Date: November 2017
3KernelVersion: 4.15
4Contact: "Mario Limonciello" <mario.limonciello@dell.com>
5Description:
6 A read-only description of Dell platform tokens
7 available on the machine.
8
9 Each token attribute is available as a pair of
10 sysfs attributes readable by a process with
11 CAP_SYS_ADMIN.
12
13 For example the token ID "5" would be available
14 as the following attributes:
15
16 0005_location
17 0005_value
18
19 Tokens will vary from machine to machine, and
20 only tokens available on that machine will be
21 displayed.
diff --git a/Documentation/ABI/testing/sysfs-platform-intel-wmi-thunderbolt b/Documentation/ABI/testing/sysfs-platform-intel-wmi-thunderbolt
new file mode 100644
index 000000000000..8af65059d519
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-intel-wmi-thunderbolt
@@ -0,0 +1,11 @@
1What: /sys/devices/platform/<platform>/force_power
2Date: September 2017
3KernelVersion: 4.15
4Contact: "Mario Limonciello" <mario.limonciello@dell.com>
5Description:
6 Modify the platform force power state, influencing
7 Thunderbolt controllers to turn on or off when no
8 devices are connected (write-only)
9 There are two available states:
10 * 0 -> Force power disabled
11 * 1 -> Force power enabled
diff --git a/Documentation/admin-guide/thunderbolt.rst b/Documentation/admin-guide/thunderbolt.rst
index 5c62d11d77e8..de50a8561774 100644
--- a/Documentation/admin-guide/thunderbolt.rst
+++ b/Documentation/admin-guide/thunderbolt.rst
@@ -221,3 +221,18 @@ The driver will create one virtual ethernet interface per Thunderbolt
221port which are named like ``thunderbolt0`` and so on. From this point 221port which are named like ``thunderbolt0`` and so on. From this point
222you can either use standard userspace tools like ``ifconfig`` to 222you can either use standard userspace tools like ``ifconfig`` to
223configure the interface or let your GUI to handle it automatically. 223configure the interface or let your GUI to handle it automatically.
224
225Forcing power
226-------------
227Many OEMs include a method that can be used to force the power of a
228thunderbolt controller to an "On" state even if nothing is connected.
229If supported by your machine this will be exposed by the WMI bus with
230a sysfs attribute called "force_power".
231
232For example the intel-wmi-thunderbolt driver exposes this attribute in:
233 /sys/devices/platform/PNP0C14:00/wmi_bus/wmi_bus-PNP0C14:00/86CCFD48-205E-4A77-9C48-2021CBEDE341/force_power
234
235 To force the power to on, write 1 to this attribute file.
236 To disable force power, write 0 to this attribute file.
237
238Note: it's currently not possible to query the force power state of a platform.
diff --git a/MAINTAINERS b/MAINTAINERS
index 16137acd7f2f..bf3cf8a8974f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -384,6 +384,7 @@ ACPI WMI DRIVER
384L: platform-driver-x86@vger.kernel.org 384L: platform-driver-x86@vger.kernel.org
385S: Orphan 385S: Orphan
386F: drivers/platform/x86/wmi.c 386F: drivers/platform/x86/wmi.c
387F: include/uapi/linux/wmi.h
387 388
388AD1889 ALSA SOUND DRIVER 389AD1889 ALSA SOUND DRIVER
389M: Thibaut Varene <T-Bone@parisc-linux.org> 390M: Thibaut Varene <T-Bone@parisc-linux.org>
@@ -4030,6 +4031,26 @@ M: "Maciej W. Rozycki" <macro@linux-mips.org>
4030S: Maintained 4031S: Maintained
4031F: drivers/net/fddi/defxx.* 4032F: drivers/net/fddi/defxx.*
4032 4033
4034DELL SMBIOS DRIVER
4035M: Pali Rohár <pali.rohar@gmail.com>
4036M: Mario Limonciello <mario.limonciello@dell.com>
4037L: platform-driver-x86@vger.kernel.org
4038S: Maintained
4039F: drivers/platform/x86/dell-smbios.*
4040
4041DELL SMBIOS SMM DRIVER
4042M: Mario Limonciello <mario.limonciello@dell.com>
4043L: platform-driver-x86@vger.kernel.org
4044S: Maintained
4045F: drivers/platform/x86/dell-smbios-smm.c
4046
4047DELL SMBIOS WMI DRIVER
4048M: Mario Limonciello <mario.limonciello@dell.com>
4049L: platform-driver-x86@vger.kernel.org
4050S: Maintained
4051F: drivers/platform/x86/dell-smbios-wmi.c
4052F: tools/wmi/dell-smbios-example.c
4053
4033DELL LAPTOP DRIVER 4054DELL LAPTOP DRIVER
4034M: Matthew Garrett <mjg59@srcf.ucam.org> 4055M: Matthew Garrett <mjg59@srcf.ucam.org>
4035M: Pali Rohár <pali.rohar@gmail.com> 4056M: Pali Rohár <pali.rohar@gmail.com>
@@ -4059,12 +4080,17 @@ S: Maintained
4059F: Documentation/dcdbas.txt 4080F: Documentation/dcdbas.txt
4060F: drivers/firmware/dcdbas.* 4081F: drivers/firmware/dcdbas.*
4061 4082
4062DELL WMI EXTRAS DRIVER 4083DELL WMI NOTIFICATIONS DRIVER
4063M: Matthew Garrett <mjg59@srcf.ucam.org> 4084M: Matthew Garrett <mjg59@srcf.ucam.org>
4064M: Pali Rohár <pali.rohar@gmail.com> 4085M: Pali Rohár <pali.rohar@gmail.com>
4065S: Maintained 4086S: Maintained
4066F: drivers/platform/x86/dell-wmi.c 4087F: drivers/platform/x86/dell-wmi.c
4067 4088
4089DELL WMI DESCRIPTOR DRIVER
4090M: Mario Limonciello <mario.limonciello@dell.com>
4091S: Maintained
4092F: drivers/platform/x86/dell-wmi-descriptor.c
4093
4068DELTA ST MEDIA DRIVER 4094DELTA ST MEDIA DRIVER
4069M: Hugues Fruchet <hugues.fruchet@st.com> 4095M: Hugues Fruchet <hugues.fruchet@st.com>
4070L: linux-media@vger.kernel.org 4096L: linux-media@vger.kernel.org
@@ -7181,6 +7207,11 @@ F: Documentation/wimax/README.i2400m
7181F: drivers/net/wimax/i2400m/ 7207F: drivers/net/wimax/i2400m/
7182F: include/uapi/linux/wimax/i2400m.h 7208F: include/uapi/linux/wimax/i2400m.h
7183 7209
7210INTEL WMI THUNDERBOLT FORCE POWER DRIVER
7211M: Mario Limonciello <mario.limonciello@dell.com>
7212S: Maintained
7213F: drivers/platform/x86/intel-wmi-thunderbolt.c
7214
7184INTEL(R) TRACE HUB 7215INTEL(R) TRACE HUB
7185M: Alexander Shishkin <alexander.shishkin@linux.intel.com> 7216M: Alexander Shishkin <alexander.shishkin@linux.intel.com>
7186S: Supported 7217S: Supported
@@ -10630,6 +10661,12 @@ S: Maintained
10630F: crypto/pcrypt.c 10661F: crypto/pcrypt.c
10631F: include/crypto/pcrypt.h 10662F: include/crypto/pcrypt.h
10632 10663
10664PEAQ WMI HOTKEYS DRIVER
10665M: Hans de Goede <hdegoede@redhat.com>
10666L: platform-driver-x86@vger.kernel.org
10667S: Maintained
10668F: drivers/platform/x86/peaq-wmi.c
10669
10633PER-CPU MEMORY ALLOCATOR 10670PER-CPU MEMORY ALLOCATOR
10634M: Tejun Heo <tj@kernel.org> 10671M: Tejun Heo <tj@kernel.org>
10635M: Christoph Lameter <cl@linux.com> 10672M: Christoph Lameter <cl@linux.com>
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 09dac11337d1..344c78f0a5c4 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -93,12 +93,33 @@ config ASUS_LAPTOP
93 93
94config DELL_SMBIOS 94config DELL_SMBIOS
95 tristate 95 tristate
96 select DCDBAS 96
97config DELL_SMBIOS_WMI
98 tristate "Dell SMBIOS calling interface (WMI implementation)"
99 depends on ACPI_WMI
100 select DELL_WMI_DESCRIPTOR
101 default ACPI_WMI
102 select DELL_SMBIOS
103 ---help---
104 This provides an implementation for the Dell SMBIOS calling interface
105 communicated over ACPI-WMI.
106
107 If you have a Dell computer from >2007 you should say Y or M here.
108 If you aren't sure and this module doesn't work for your computer
109 it just won't load.
110
111config DELL_SMBIOS_SMM
112 tristate "Dell SMBIOS calling interface (SMM implementation)"
113 depends on DCDBAS
114 default DCDBAS
115 select DELL_SMBIOS
97 ---help--- 116 ---help---
98 This module provides common functions for kernel modules using 117 This provides an implementation for the Dell SMBIOS calling interface
99 Dell SMBIOS. 118 communicated over SMI/SMM.
100 119
101 If you have a Dell laptop, say Y or M here. 120 If you have a Dell computer from <=2017 you should say Y or M here.
121 If you aren't sure and this module doesn't work for your computer
122 it just won't load.
102 123
103config DELL_LAPTOP 124config DELL_LAPTOP
104 tristate "Dell Laptop Extras" 125 tristate "Dell Laptop Extras"
@@ -116,11 +137,12 @@ config DELL_LAPTOP
116 laptops (except for some models covered by the Compal driver). 137 laptops (except for some models covered by the Compal driver).
117 138
118config DELL_WMI 139config DELL_WMI
119 tristate "Dell WMI extras" 140 tristate "Dell WMI notifications"
120 depends on ACPI_WMI 141 depends on ACPI_WMI
121 depends on DMI 142 depends on DMI
122 depends on INPUT 143 depends on INPUT
123 depends on ACPI_VIDEO || ACPI_VIDEO = n 144 depends on ACPI_VIDEO || ACPI_VIDEO = n
145 select DELL_WMI_DESCRIPTOR
124 select DELL_SMBIOS 146 select DELL_SMBIOS
125 select INPUT_SPARSEKMAP 147 select INPUT_SPARSEKMAP
126 ---help--- 148 ---help---
@@ -129,6 +151,10 @@ config DELL_WMI
129 To compile this driver as a module, choose M here: the module will 151 To compile this driver as a module, choose M here: the module will
130 be called dell-wmi. 152 be called dell-wmi.
131 153
154config DELL_WMI_DESCRIPTOR
155 tristate
156 depends on ACPI_WMI
157
132config DELL_WMI_AIO 158config DELL_WMI_AIO
133 tristate "WMI Hotkeys for Dell All-In-One series" 159 tristate "WMI Hotkeys for Dell All-In-One series"
134 depends on ACPI_WMI 160 depends on ACPI_WMI
@@ -658,6 +684,19 @@ config WMI_BMOF
658 To compile this driver as a module, choose M here: the module will 684 To compile this driver as a module, choose M here: the module will
659 be called wmi-bmof. 685 be called wmi-bmof.
660 686
687config INTEL_WMI_THUNDERBOLT
688 tristate "Intel WMI thunderbolt force power driver"
689 depends on ACPI_WMI
690 default ACPI_WMI
691 ---help---
692 Say Y here if you want to be able to use the WMI interface on select
693 systems to force the power control of Intel Thunderbolt controllers.
694 This is useful for updating the firmware when devices are not plugged
695 into the controller.
696
697 To compile this driver as a module, choose M here: the module will
698 be called intel-wmi-thunderbolt.
699
661config MSI_WMI 700config MSI_WMI
662 tristate "MSI WMI extras" 701 tristate "MSI WMI extras"
663 depends on ACPI_WMI 702 depends on ACPI_WMI
@@ -793,7 +832,7 @@ config ACPI_CMPC
793 832
794config INTEL_CHT_INT33FE 833config INTEL_CHT_INT33FE
795 tristate "Intel Cherry Trail ACPI INT33FE Driver" 834 tristate "Intel Cherry Trail ACPI INT33FE Driver"
796 depends on X86 && ACPI && I2C 835 depends on X86 && ACPI && I2C && REGULATOR
797 ---help--- 836 ---help---
798 This driver add support for the INT33FE ACPI device found on 837 This driver add support for the INT33FE ACPI device found on
799 some Intel Cherry Trail devices. 838 some Intel Cherry Trail devices.
@@ -804,6 +843,10 @@ config INTEL_CHT_INT33FE
804 This driver instantiates i2c-clients for these, so that standard 843 This driver instantiates i2c-clients for these, so that standard
805 i2c drivers for these chips can bind to the them. 844 i2c drivers for these chips can bind to the them.
806 845
846 If you enable this driver it is advised to also select
847 CONFIG_TYPEC_FUSB302=m, CONFIG_CHARGER_BQ24190=m and
848 CONFIG_BATTERY_MAX17042=m.
849
807config INTEL_INT0002_VGPIO 850config INTEL_INT0002_VGPIO
808 tristate "Intel ACPI INT0002 Virtual GPIO driver" 851 tristate "Intel ACPI INT0002 Virtual GPIO driver"
809 depends on GPIOLIB && ACPI 852 depends on GPIOLIB && ACPI
@@ -1088,7 +1131,6 @@ config INTEL_PUNIT_IPC
1088 1131
1089config INTEL_TELEMETRY 1132config INTEL_TELEMETRY
1090 tristate "Intel SoC Telemetry Driver" 1133 tristate "Intel SoC Telemetry Driver"
1091 default n
1092 depends on INTEL_PMC_IPC && INTEL_PUNIT_IPC && X86_64 1134 depends on INTEL_PMC_IPC && INTEL_PUNIT_IPC && X86_64
1093 ---help--- 1135 ---help---
1094 This driver provides interfaces to configure and use 1136 This driver provides interfaces to configure and use
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index f9e3ae683bbe..c32b34a72467 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -13,8 +13,11 @@ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
13obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o 13obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o
14obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o 14obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
15obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o 15obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o
16obj-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o
17obj-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o
16obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o 18obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o
17obj-$(CONFIG_DELL_WMI) += dell-wmi.o 19obj-$(CONFIG_DELL_WMI) += dell-wmi.o
20obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o
18obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o 21obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o
19obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o 22obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o
20obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o 23obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o
@@ -40,6 +43,7 @@ obj-$(CONFIG_PEAQ_WMI) += peaq-wmi.o
40obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o 43obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o
41obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o 44obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
42obj-$(CONFIG_WMI_BMOF) += wmi-bmof.o 45obj-$(CONFIG_WMI_BMOF) += wmi-bmof.o
46obj-$(CONFIG_INTEL_WMI_THUNDERBOLT) += intel-wmi-thunderbolt.o
43 47
44# toshiba_acpi must link after wmi to ensure that wmi devices are found 48# toshiba_acpi must link after wmi to ensure that wmi devices are found
45# before toshiba_acpi initializes 49# before toshiba_acpi initializes
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 48e1541dc8d4..a32c5c00e0e7 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -119,6 +119,7 @@ MODULE_LICENSE("GPL");
119#define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012 119#define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012
120#define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021 120#define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021
121#define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022 /* ?? */ 121#define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022 /* ?? */
122#define ASUS_WMI_DEVID_LIGHTBAR 0x00050025
122 123
123/* Misc */ 124/* Misc */
124#define ASUS_WMI_DEVID_CAMERA 0x00060013 125#define ASUS_WMI_DEVID_CAMERA 0x00060013
@@ -148,6 +149,7 @@ MODULE_LICENSE("GPL");
148#define ASUS_WMI_DSTS_BIOS_BIT 0x00040000 149#define ASUS_WMI_DSTS_BIOS_BIT 0x00040000
149#define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF 150#define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF
150#define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00 151#define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00
152#define ASUS_WMI_DSTS_LIGHTBAR_MASK 0x0000000F
151 153
152#define ASUS_FAN_DESC "cpu_fan" 154#define ASUS_FAN_DESC "cpu_fan"
153#define ASUS_FAN_MFUN 0x13 155#define ASUS_FAN_MFUN 0x13
@@ -222,10 +224,13 @@ struct asus_wmi {
222 int tpd_led_wk; 224 int tpd_led_wk;
223 struct led_classdev kbd_led; 225 struct led_classdev kbd_led;
224 int kbd_led_wk; 226 int kbd_led_wk;
227 struct led_classdev lightbar_led;
228 int lightbar_led_wk;
225 struct workqueue_struct *led_workqueue; 229 struct workqueue_struct *led_workqueue;
226 struct work_struct tpd_led_work; 230 struct work_struct tpd_led_work;
227 struct work_struct kbd_led_work; 231 struct work_struct kbd_led_work;
228 struct work_struct wlan_led_work; 232 struct work_struct wlan_led_work;
233 struct work_struct lightbar_led_work;
229 234
230 struct asus_rfkill wlan; 235 struct asus_rfkill wlan;
231 struct asus_rfkill bluetooth; 236 struct asus_rfkill bluetooth;
@@ -567,6 +572,48 @@ static enum led_brightness wlan_led_get(struct led_classdev *led_cdev)
567 return result & ASUS_WMI_DSTS_BRIGHTNESS_MASK; 572 return result & ASUS_WMI_DSTS_BRIGHTNESS_MASK;
568} 573}
569 574
575static void lightbar_led_update(struct work_struct *work)
576{
577 struct asus_wmi *asus;
578 int ctrl_param;
579
580 asus = container_of(work, struct asus_wmi, lightbar_led_work);
581
582 ctrl_param = asus->lightbar_led_wk;
583 asus_wmi_set_devstate(ASUS_WMI_DEVID_LIGHTBAR, ctrl_param, NULL);
584}
585
586static void lightbar_led_set(struct led_classdev *led_cdev,
587 enum led_brightness value)
588{
589 struct asus_wmi *asus;
590
591 asus = container_of(led_cdev, struct asus_wmi, lightbar_led);
592
593 asus->lightbar_led_wk = !!value;
594 queue_work(asus->led_workqueue, &asus->lightbar_led_work);
595}
596
597static enum led_brightness lightbar_led_get(struct led_classdev *led_cdev)
598{
599 struct asus_wmi *asus;
600 u32 result;
601
602 asus = container_of(led_cdev, struct asus_wmi, lightbar_led);
603 asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_LIGHTBAR, &result);
604
605 return result & ASUS_WMI_DSTS_LIGHTBAR_MASK;
606}
607
608static int lightbar_led_presence(struct asus_wmi *asus)
609{
610 u32 result;
611
612 asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_LIGHTBAR, &result);
613
614 return result & ASUS_WMI_DSTS_PRESENCE_BIT;
615}
616
570static void asus_wmi_led_exit(struct asus_wmi *asus) 617static void asus_wmi_led_exit(struct asus_wmi *asus)
571{ 618{
572 if (!IS_ERR_OR_NULL(asus->kbd_led.dev)) 619 if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
@@ -575,6 +622,8 @@ static void asus_wmi_led_exit(struct asus_wmi *asus)
575 led_classdev_unregister(&asus->tpd_led); 622 led_classdev_unregister(&asus->tpd_led);
576 if (!IS_ERR_OR_NULL(asus->wlan_led.dev)) 623 if (!IS_ERR_OR_NULL(asus->wlan_led.dev))
577 led_classdev_unregister(&asus->wlan_led); 624 led_classdev_unregister(&asus->wlan_led);
625 if (!IS_ERR_OR_NULL(asus->lightbar_led.dev))
626 led_classdev_unregister(&asus->lightbar_led);
578 if (asus->led_workqueue) 627 if (asus->led_workqueue)
579 destroy_workqueue(asus->led_workqueue); 628 destroy_workqueue(asus->led_workqueue);
580} 629}
@@ -630,6 +679,20 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
630 679
631 rv = led_classdev_register(&asus->platform_device->dev, 680 rv = led_classdev_register(&asus->platform_device->dev,
632 &asus->wlan_led); 681 &asus->wlan_led);
682 if (rv)
683 goto error;
684 }
685
686 if (lightbar_led_presence(asus)) {
687 INIT_WORK(&asus->lightbar_led_work, lightbar_led_update);
688
689 asus->lightbar_led.name = "asus::lightbar";
690 asus->lightbar_led.brightness_set = lightbar_led_set;
691 asus->lightbar_led.brightness_get = lightbar_led_get;
692 asus->lightbar_led.max_brightness = 1;
693
694 rv = led_classdev_register(&asus->platform_device->dev,
695 &asus->lightbar_led);
633 } 696 }
634 697
635error: 698error:
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index f42159fd2031..2d704361f672 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -35,18 +35,6 @@
35#include "dell-rbtn.h" 35#include "dell-rbtn.h"
36#include "dell-smbios.h" 36#include "dell-smbios.h"
37 37
38#define BRIGHTNESS_TOKEN 0x7d
39#define KBD_LED_OFF_TOKEN 0x01E1
40#define KBD_LED_ON_TOKEN 0x01E2
41#define KBD_LED_AUTO_TOKEN 0x01E3
42#define KBD_LED_AUTO_25_TOKEN 0x02EA
43#define KBD_LED_AUTO_50_TOKEN 0x02EB
44#define KBD_LED_AUTO_75_TOKEN 0x02EC
45#define KBD_LED_AUTO_100_TOKEN 0x02F6
46#define GLOBAL_MIC_MUTE_ENABLE 0x0364
47#define GLOBAL_MIC_MUTE_DISABLE 0x0365
48#define KBD_LED_AC_TOKEN 0x0451
49
50struct quirk_entry { 38struct quirk_entry {
51 u8 touchpad_led; 39 u8 touchpad_led;
52 40
@@ -85,6 +73,7 @@ static struct platform_driver platform_driver = {
85 } 73 }
86}; 74};
87 75
76static struct calling_interface_buffer *buffer;
88static struct platform_device *platform_device; 77static struct platform_device *platform_device;
89static struct backlight_device *dell_backlight_device; 78static struct backlight_device *dell_backlight_device;
90static struct rfkill *wifi_rfkill; 79static struct rfkill *wifi_rfkill;
@@ -283,6 +272,27 @@ static const struct dmi_system_id dell_quirks[] __initconst = {
283 { } 272 { }
284}; 273};
285 274
275void dell_set_arguments(u32 arg0, u32 arg1, u32 arg2, u32 arg3)
276{
277 memset(buffer, 0, sizeof(struct calling_interface_buffer));
278 buffer->input[0] = arg0;
279 buffer->input[1] = arg1;
280 buffer->input[2] = arg2;
281 buffer->input[3] = arg3;
282}
283
284int dell_send_request(u16 class, u16 select)
285{
286 int ret;
287
288 buffer->cmd_class = class;
289 buffer->cmd_select = select;
290 ret = dell_smbios_call(buffer);
291 if (ret != 0)
292 return ret;
293 return dell_smbios_error(buffer->output[0]);
294}
295
286/* 296/*
287 * Derived from information in smbios-wireless-ctl: 297 * Derived from information in smbios-wireless-ctl:
288 * 298 *
@@ -405,7 +415,6 @@ static const struct dmi_system_id dell_quirks[] __initconst = {
405 415
406static int dell_rfkill_set(void *data, bool blocked) 416static int dell_rfkill_set(void *data, bool blocked)
407{ 417{
408 struct calling_interface_buffer *buffer;
409 int disable = blocked ? 1 : 0; 418 int disable = blocked ? 1 : 0;
410 unsigned long radio = (unsigned long)data; 419 unsigned long radio = (unsigned long)data;
411 int hwswitch_bit = (unsigned long)data - 1; 420 int hwswitch_bit = (unsigned long)data - 1;
@@ -413,20 +422,16 @@ static int dell_rfkill_set(void *data, bool blocked)
413 int status; 422 int status;
414 int ret; 423 int ret;
415 424
416 buffer = dell_smbios_get_buffer(); 425 dell_set_arguments(0, 0, 0, 0);
417 426 ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
418 dell_smbios_send_request(17, 11); 427 if (ret)
419 ret = buffer->output[0]; 428 return ret;
420 status = buffer->output[1]; 429 status = buffer->output[1];
421 430
422 if (ret != 0) 431 dell_set_arguments(0x2, 0, 0, 0);
423 goto out; 432 ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
424 433 if (ret)
425 dell_smbios_clear_buffer(); 434 return ret;
426
427 buffer->input[0] = 0x2;
428 dell_smbios_send_request(17, 11);
429 ret = buffer->output[0];
430 hwswitch = buffer->output[1]; 435 hwswitch = buffer->output[1];
431 436
432 /* If the hardware switch controls this radio, and the hardware 437 /* If the hardware switch controls this radio, and the hardware
@@ -435,28 +440,19 @@ static int dell_rfkill_set(void *data, bool blocked)
435 (status & BIT(0)) && !(status & BIT(16))) 440 (status & BIT(0)) && !(status & BIT(16)))
436 disable = 1; 441 disable = 1;
437 442
438 dell_smbios_clear_buffer(); 443 dell_set_arguments(1 | (radio<<8) | (disable << 16), 0, 0, 0);
439 444 ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
440 buffer->input[0] = (1 | (radio<<8) | (disable << 16)); 445 return ret;
441 dell_smbios_send_request(17, 11);
442 ret = buffer->output[0];
443
444 out:
445 dell_smbios_release_buffer();
446 return dell_smbios_error(ret);
447} 446}
448 447
449/* Must be called with the buffer held */
450static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio, 448static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio,
451 int status, 449 int status)
452 struct calling_interface_buffer *buffer)
453{ 450{
454 if (status & BIT(0)) { 451 if (status & BIT(0)) {
455 /* Has hw-switch, sync sw_state to BIOS */ 452 /* Has hw-switch, sync sw_state to BIOS */
456 int block = rfkill_blocked(rfkill); 453 int block = rfkill_blocked(rfkill);
457 dell_smbios_clear_buffer(); 454 dell_set_arguments(1 | (radio << 8) | (block << 16), 0, 0, 0);
458 buffer->input[0] = (1 | (radio << 8) | (block << 16)); 455 dell_send_request(CLASS_INFO, SELECT_RFKILL);
459 dell_smbios_send_request(17, 11);
460 } else { 456 } else {
461 /* No hw-switch, sync BIOS state to sw_state */ 457 /* No hw-switch, sync BIOS state to sw_state */
462 rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16))); 458 rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16)));
@@ -472,32 +468,23 @@ static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio,
472 468
473static void dell_rfkill_query(struct rfkill *rfkill, void *data) 469static void dell_rfkill_query(struct rfkill *rfkill, void *data)
474{ 470{
475 struct calling_interface_buffer *buffer;
476 int radio = ((unsigned long)data & 0xF); 471 int radio = ((unsigned long)data & 0xF);
477 int hwswitch; 472 int hwswitch;
478 int status; 473 int status;
479 int ret; 474 int ret;
480 475
481 buffer = dell_smbios_get_buffer(); 476 dell_set_arguments(0, 0, 0, 0);
482 477 ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
483 dell_smbios_send_request(17, 11);
484 ret = buffer->output[0];
485 status = buffer->output[1]; 478 status = buffer->output[1];
486 479
487 if (ret != 0 || !(status & BIT(0))) { 480 if (ret != 0 || !(status & BIT(0))) {
488 dell_smbios_release_buffer();
489 return; 481 return;
490 } 482 }
491 483
492 dell_smbios_clear_buffer(); 484 dell_set_arguments(0, 0x2, 0, 0);
493 485 ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
494 buffer->input[0] = 0x2;
495 dell_smbios_send_request(17, 11);
496 ret = buffer->output[0];
497 hwswitch = buffer->output[1]; 486 hwswitch = buffer->output[1];
498 487
499 dell_smbios_release_buffer();
500
501 if (ret != 0) 488 if (ret != 0)
502 return; 489 return;
503 490
@@ -513,27 +500,23 @@ static struct dentry *dell_laptop_dir;
513 500
514static int dell_debugfs_show(struct seq_file *s, void *data) 501static int dell_debugfs_show(struct seq_file *s, void *data)
515{ 502{
516 struct calling_interface_buffer *buffer;
517 int hwswitch_state; 503 int hwswitch_state;
518 int hwswitch_ret; 504 int hwswitch_ret;
519 int status; 505 int status;
520 int ret; 506 int ret;
521 507
522 buffer = dell_smbios_get_buffer(); 508 dell_set_arguments(0, 0, 0, 0);
523 509 ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
524 dell_smbios_send_request(17, 11); 510 if (ret)
525 ret = buffer->output[0]; 511 return ret;
526 status = buffer->output[1]; 512 status = buffer->output[1];
527 513
528 dell_smbios_clear_buffer(); 514 dell_set_arguments(0, 0x2, 0, 0);
529 515 hwswitch_ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
530 buffer->input[0] = 0x2; 516 if (hwswitch_ret)
531 dell_smbios_send_request(17, 11); 517 return hwswitch_ret;
532 hwswitch_ret = buffer->output[0];
533 hwswitch_state = buffer->output[1]; 518 hwswitch_state = buffer->output[1];
534 519
535 dell_smbios_release_buffer();
536
537 seq_printf(s, "return:\t%d\n", ret); 520 seq_printf(s, "return:\t%d\n", ret);
538 seq_printf(s, "status:\t0x%X\n", status); 521 seq_printf(s, "status:\t0x%X\n", status);
539 seq_printf(s, "Bit 0 : Hardware switch supported: %lu\n", 522 seq_printf(s, "Bit 0 : Hardware switch supported: %lu\n",
@@ -613,46 +596,36 @@ static const struct file_operations dell_debugfs_fops = {
613 596
614static void dell_update_rfkill(struct work_struct *ignored) 597static void dell_update_rfkill(struct work_struct *ignored)
615{ 598{
616 struct calling_interface_buffer *buffer;
617 int hwswitch = 0; 599 int hwswitch = 0;
618 int status; 600 int status;
619 int ret; 601 int ret;
620 602
621 buffer = dell_smbios_get_buffer(); 603 dell_set_arguments(0, 0, 0, 0);
622 604 ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
623 dell_smbios_send_request(17, 11);
624 ret = buffer->output[0];
625 status = buffer->output[1]; 605 status = buffer->output[1];
626 606
627 if (ret != 0) 607 if (ret != 0)
628 goto out; 608 return;
629
630 dell_smbios_clear_buffer();
631 609
632 buffer->input[0] = 0x2; 610 dell_set_arguments(0, 0x2, 0, 0);
633 dell_smbios_send_request(17, 11); 611 ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
634 ret = buffer->output[0];
635 612
636 if (ret == 0 && (status & BIT(0))) 613 if (ret == 0 && (status & BIT(0)))
637 hwswitch = buffer->output[1]; 614 hwswitch = buffer->output[1];
638 615
639 if (wifi_rfkill) { 616 if (wifi_rfkill) {
640 dell_rfkill_update_hw_state(wifi_rfkill, 1, status, hwswitch); 617 dell_rfkill_update_hw_state(wifi_rfkill, 1, status, hwswitch);
641 dell_rfkill_update_sw_state(wifi_rfkill, 1, status, buffer); 618 dell_rfkill_update_sw_state(wifi_rfkill, 1, status);
642 } 619 }
643 if (bluetooth_rfkill) { 620 if (bluetooth_rfkill) {
644 dell_rfkill_update_hw_state(bluetooth_rfkill, 2, status, 621 dell_rfkill_update_hw_state(bluetooth_rfkill, 2, status,
645 hwswitch); 622 hwswitch);
646 dell_rfkill_update_sw_state(bluetooth_rfkill, 2, status, 623 dell_rfkill_update_sw_state(bluetooth_rfkill, 2, status);
647 buffer);
648 } 624 }
649 if (wwan_rfkill) { 625 if (wwan_rfkill) {
650 dell_rfkill_update_hw_state(wwan_rfkill, 3, status, hwswitch); 626 dell_rfkill_update_hw_state(wwan_rfkill, 3, status, hwswitch);
651 dell_rfkill_update_sw_state(wwan_rfkill, 3, status, buffer); 627 dell_rfkill_update_sw_state(wwan_rfkill, 3, status);
652 } 628 }
653
654 out:
655 dell_smbios_release_buffer();
656} 629}
657static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill); 630static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill);
658 631
@@ -696,7 +669,6 @@ static struct notifier_block dell_laptop_rbtn_notifier = {
696 669
697static int __init dell_setup_rfkill(void) 670static int __init dell_setup_rfkill(void)
698{ 671{
699 struct calling_interface_buffer *buffer;
700 int status, ret, whitelisted; 672 int status, ret, whitelisted;
701 const char *product; 673 const char *product;
702 674
@@ -712,11 +684,9 @@ static int __init dell_setup_rfkill(void)
712 if (!force_rfkill && !whitelisted) 684 if (!force_rfkill && !whitelisted)
713 return 0; 685 return 0;
714 686
715 buffer = dell_smbios_get_buffer(); 687 dell_set_arguments(0, 0, 0, 0);
716 dell_smbios_send_request(17, 11); 688 ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
717 ret = buffer->output[0];
718 status = buffer->output[1]; 689 status = buffer->output[1];
719 dell_smbios_release_buffer();
720 690
721 /* dell wireless info smbios call is not supported */ 691 /* dell wireless info smbios call is not supported */
722 if (ret != 0) 692 if (ret != 0)
@@ -869,7 +839,6 @@ static void dell_cleanup_rfkill(void)
869 839
870static int dell_send_intensity(struct backlight_device *bd) 840static int dell_send_intensity(struct backlight_device *bd)
871{ 841{
872 struct calling_interface_buffer *buffer;
873 struct calling_interface_token *token; 842 struct calling_interface_token *token;
874 int ret; 843 int ret;
875 844
@@ -877,24 +846,17 @@ static int dell_send_intensity(struct backlight_device *bd)
877 if (!token) 846 if (!token)
878 return -ENODEV; 847 return -ENODEV;
879 848
880 buffer = dell_smbios_get_buffer(); 849 dell_set_arguments(token->location, bd->props.brightness, 0, 0);
881 buffer->input[0] = token->location;
882 buffer->input[1] = bd->props.brightness;
883
884 if (power_supply_is_system_supplied() > 0) 850 if (power_supply_is_system_supplied() > 0)
885 dell_smbios_send_request(1, 2); 851 ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_AC);
886 else 852 else
887 dell_smbios_send_request(1, 1); 853 ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT);
888 854
889 ret = dell_smbios_error(buffer->output[0]);
890
891 dell_smbios_release_buffer();
892 return ret; 855 return ret;
893} 856}
894 857
895static int dell_get_intensity(struct backlight_device *bd) 858static int dell_get_intensity(struct backlight_device *bd)
896{ 859{
897 struct calling_interface_buffer *buffer;
898 struct calling_interface_token *token; 860 struct calling_interface_token *token;
899 int ret; 861 int ret;
900 862
@@ -902,20 +864,14 @@ static int dell_get_intensity(struct backlight_device *bd)
902 if (!token) 864 if (!token)
903 return -ENODEV; 865 return -ENODEV;
904 866
905 buffer = dell_smbios_get_buffer(); 867 dell_set_arguments(token->location, 0, 0, 0);
906 buffer->input[0] = token->location;
907
908 if (power_supply_is_system_supplied() > 0) 868 if (power_supply_is_system_supplied() > 0)
909 dell_smbios_send_request(0, 2); 869 ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_AC);
910 else 870 else
911 dell_smbios_send_request(0, 1); 871 ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_BAT);
912 872
913 if (buffer->output[0]) 873 if (ret == 0)
914 ret = dell_smbios_error(buffer->output[0]);
915 else
916 ret = buffer->output[1]; 874 ret = buffer->output[1];
917
918 dell_smbios_release_buffer();
919 return ret; 875 return ret;
920} 876}
921 877
@@ -1179,20 +1135,13 @@ static DEFINE_MUTEX(kbd_led_mutex);
1179 1135
1180static int kbd_get_info(struct kbd_info *info) 1136static int kbd_get_info(struct kbd_info *info)
1181{ 1137{
1182 struct calling_interface_buffer *buffer;
1183 u8 units; 1138 u8 units;
1184 int ret; 1139 int ret;
1185 1140
1186 buffer = dell_smbios_get_buffer(); 1141 dell_set_arguments(0, 0, 0, 0);
1187 1142 ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
1188 buffer->input[0] = 0x0; 1143 if (ret)
1189 dell_smbios_send_request(4, 11); 1144 return ret;
1190 ret = buffer->output[0];
1191
1192 if (ret) {
1193 ret = dell_smbios_error(ret);
1194 goto out;
1195 }
1196 1145
1197 info->modes = buffer->output[1] & 0xFFFF; 1146 info->modes = buffer->output[1] & 0xFFFF;
1198 info->type = (buffer->output[1] >> 24) & 0xFF; 1147 info->type = (buffer->output[1] >> 24) & 0xFF;
@@ -1209,8 +1158,6 @@ static int kbd_get_info(struct kbd_info *info)
1209 if (units & BIT(3)) 1158 if (units & BIT(3))
1210 info->days = (buffer->output[3] >> 24) & 0xFF; 1159 info->days = (buffer->output[3] >> 24) & 0xFF;
1211 1160
1212 out:
1213 dell_smbios_release_buffer();
1214 return ret; 1161 return ret;
1215} 1162}
1216 1163
@@ -1269,19 +1216,12 @@ static int kbd_set_level(struct kbd_state *state, u8 level)
1269 1216
1270static int kbd_get_state(struct kbd_state *state) 1217static int kbd_get_state(struct kbd_state *state)
1271{ 1218{
1272 struct calling_interface_buffer *buffer;
1273 int ret; 1219 int ret;
1274 1220
1275 buffer = dell_smbios_get_buffer(); 1221 dell_set_arguments(0x1, 0, 0, 0);
1276 1222 ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
1277 buffer->input[0] = 0x1; 1223 if (ret)
1278 dell_smbios_send_request(4, 11); 1224 return ret;
1279 ret = buffer->output[0];
1280
1281 if (ret) {
1282 ret = dell_smbios_error(ret);
1283 goto out;
1284 }
1285 1225
1286 state->mode_bit = ffs(buffer->output[1] & 0xFFFF); 1226 state->mode_bit = ffs(buffer->output[1] & 0xFFFF);
1287 if (state->mode_bit != 0) 1227 if (state->mode_bit != 0)
@@ -1296,31 +1236,27 @@ static int kbd_get_state(struct kbd_state *state)
1296 state->timeout_value_ac = (buffer->output[2] >> 24) & 0x3F; 1236 state->timeout_value_ac = (buffer->output[2] >> 24) & 0x3F;
1297 state->timeout_unit_ac = (buffer->output[2] >> 30) & 0x3; 1237 state->timeout_unit_ac = (buffer->output[2] >> 30) & 0x3;
1298 1238
1299 out:
1300 dell_smbios_release_buffer();
1301 return ret; 1239 return ret;
1302} 1240}
1303 1241
1304static int kbd_set_state(struct kbd_state *state) 1242static int kbd_set_state(struct kbd_state *state)
1305{ 1243{
1306 struct calling_interface_buffer *buffer;
1307 int ret; 1244 int ret;
1245 u32 input1;
1246 u32 input2;
1247
1248 input1 = BIT(state->mode_bit) & 0xFFFF;
1249 input1 |= (state->triggers & 0xFF) << 16;
1250 input1 |= (state->timeout_value & 0x3F) << 24;
1251 input1 |= (state->timeout_unit & 0x3) << 30;
1252 input2 = state->als_setting & 0xFF;
1253 input2 |= (state->level & 0xFF) << 16;
1254 input2 |= (state->timeout_value_ac & 0x3F) << 24;
1255 input2 |= (state->timeout_unit_ac & 0x3) << 30;
1256 dell_set_arguments(0x2, input1, input2, 0);
1257 ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
1308 1258
1309 buffer = dell_smbios_get_buffer(); 1259 return ret;
1310 buffer->input[0] = 0x2;
1311 buffer->input[1] = BIT(state->mode_bit) & 0xFFFF;
1312 buffer->input[1] |= (state->triggers & 0xFF) << 16;
1313 buffer->input[1] |= (state->timeout_value & 0x3F) << 24;
1314 buffer->input[1] |= (state->timeout_unit & 0x3) << 30;
1315 buffer->input[2] = state->als_setting & 0xFF;
1316 buffer->input[2] |= (state->level & 0xFF) << 16;
1317 buffer->input[2] |= (state->timeout_value_ac & 0x3F) << 24;
1318 buffer->input[2] |= (state->timeout_unit_ac & 0x3) << 30;
1319 dell_smbios_send_request(4, 11);
1320 ret = buffer->output[0];
1321 dell_smbios_release_buffer();
1322
1323 return dell_smbios_error(ret);
1324} 1260}
1325 1261
1326static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old) 1262static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old)
@@ -1345,7 +1281,6 @@ static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old)
1345 1281
1346static int kbd_set_token_bit(u8 bit) 1282static int kbd_set_token_bit(u8 bit)
1347{ 1283{
1348 struct calling_interface_buffer *buffer;
1349 struct calling_interface_token *token; 1284 struct calling_interface_token *token;
1350 int ret; 1285 int ret;
1351 1286
@@ -1356,19 +1291,14 @@ static int kbd_set_token_bit(u8 bit)
1356 if (!token) 1291 if (!token)
1357 return -EINVAL; 1292 return -EINVAL;
1358 1293
1359 buffer = dell_smbios_get_buffer(); 1294 dell_set_arguments(token->location, token->value, 0, 0);
1360 buffer->input[0] = token->location; 1295 ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
1361 buffer->input[1] = token->value;
1362 dell_smbios_send_request(1, 0);
1363 ret = buffer->output[0];
1364 dell_smbios_release_buffer();
1365 1296
1366 return dell_smbios_error(ret); 1297 return ret;
1367} 1298}
1368 1299
1369static int kbd_get_token_bit(u8 bit) 1300static int kbd_get_token_bit(u8 bit)
1370{ 1301{
1371 struct calling_interface_buffer *buffer;
1372 struct calling_interface_token *token; 1302 struct calling_interface_token *token;
1373 int ret; 1303 int ret;
1374 int val; 1304 int val;
@@ -1380,15 +1310,12 @@ static int kbd_get_token_bit(u8 bit)
1380 if (!token) 1310 if (!token)
1381 return -EINVAL; 1311 return -EINVAL;
1382 1312
1383 buffer = dell_smbios_get_buffer(); 1313 dell_set_arguments(token->location, 0, 0, 0);
1384 buffer->input[0] = token->location; 1314 ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_STD);
1385 dell_smbios_send_request(0, 0);
1386 ret = buffer->output[0];
1387 val = buffer->output[1]; 1315 val = buffer->output[1];
1388 dell_smbios_release_buffer();
1389 1316
1390 if (ret) 1317 if (ret)
1391 return dell_smbios_error(ret); 1318 return ret;
1392 1319
1393 return (val == token->value); 1320 return (val == token->value);
1394} 1321}
@@ -2102,7 +2029,6 @@ static struct notifier_block dell_laptop_notifier = {
2102 2029
2103int dell_micmute_led_set(int state) 2030int dell_micmute_led_set(int state)
2104{ 2031{
2105 struct calling_interface_buffer *buffer;
2106 struct calling_interface_token *token; 2032 struct calling_interface_token *token;
2107 2033
2108 if (state == 0) 2034 if (state == 0)
@@ -2115,11 +2041,8 @@ int dell_micmute_led_set(int state)
2115 if (!token) 2041 if (!token)
2116 return -ENODEV; 2042 return -ENODEV;
2117 2043
2118 buffer = dell_smbios_get_buffer(); 2044 dell_set_arguments(token->location, token->value, 0, 0);
2119 buffer->input[0] = token->location; 2045 dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
2120 buffer->input[1] = token->value;
2121 dell_smbios_send_request(1, 0);
2122 dell_smbios_release_buffer();
2123 2046
2124 return state; 2047 return state;
2125} 2048}
@@ -2127,7 +2050,6 @@ EXPORT_SYMBOL_GPL(dell_micmute_led_set);
2127 2050
2128static int __init dell_init(void) 2051static int __init dell_init(void)
2129{ 2052{
2130 struct calling_interface_buffer *buffer;
2131 struct calling_interface_token *token; 2053 struct calling_interface_token *token;
2132 int max_intensity = 0; 2054 int max_intensity = 0;
2133 int ret; 2055 int ret;
@@ -2151,6 +2073,11 @@ static int __init dell_init(void)
2151 if (ret) 2073 if (ret)
2152 goto fail_platform_device2; 2074 goto fail_platform_device2;
2153 2075
2076 buffer = kzalloc(sizeof(struct calling_interface_buffer), GFP_KERNEL);
2077 if (!buffer)
2078 goto fail_buffer;
2079
2080
2154 ret = dell_setup_rfkill(); 2081 ret = dell_setup_rfkill();
2155 2082
2156 if (ret) { 2083 if (ret) {
@@ -2175,12 +2102,10 @@ static int __init dell_init(void)
2175 2102
2176 token = dell_smbios_find_token(BRIGHTNESS_TOKEN); 2103 token = dell_smbios_find_token(BRIGHTNESS_TOKEN);
2177 if (token) { 2104 if (token) {
2178 buffer = dell_smbios_get_buffer(); 2105 dell_set_arguments(token->location, 0, 0, 0);
2179 buffer->input[0] = token->location; 2106 ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_AC);
2180 dell_smbios_send_request(0, 2); 2107 if (ret)
2181 if (buffer->output[0] == 0)
2182 max_intensity = buffer->output[3]; 2108 max_intensity = buffer->output[3];
2183 dell_smbios_release_buffer();
2184 } 2109 }
2185 2110
2186 if (max_intensity) { 2111 if (max_intensity) {
@@ -2214,6 +2139,8 @@ static int __init dell_init(void)
2214fail_get_brightness: 2139fail_get_brightness:
2215 backlight_device_unregister(dell_backlight_device); 2140 backlight_device_unregister(dell_backlight_device);
2216fail_backlight: 2141fail_backlight:
2142 kfree(buffer);
2143fail_buffer:
2217 dell_cleanup_rfkill(); 2144 dell_cleanup_rfkill();
2218fail_rfkill: 2145fail_rfkill:
2219 platform_device_del(platform_device); 2146 platform_device_del(platform_device);
@@ -2233,6 +2160,7 @@ static void __exit dell_exit(void)
2233 touchpad_led_exit(); 2160 touchpad_led_exit();
2234 kbd_led_exit(); 2161 kbd_led_exit();
2235 backlight_device_unregister(dell_backlight_device); 2162 backlight_device_unregister(dell_backlight_device);
2163 kfree(buffer);
2236 dell_cleanup_rfkill(); 2164 dell_cleanup_rfkill();
2237 if (platform_device) { 2165 if (platform_device) {
2238 platform_device_unregister(platform_device); 2166 platform_device_unregister(platform_device);
diff --git a/drivers/platform/x86/dell-smbios-smm.c b/drivers/platform/x86/dell-smbios-smm.c
new file mode 100644
index 000000000000..89f65c4651a0
--- /dev/null
+++ b/drivers/platform/x86/dell-smbios-smm.c
@@ -0,0 +1,196 @@
1/*
2 * SMI methods for use with dell-smbios
3 *
4 * Copyright (c) Red Hat <mjg@redhat.com>
5 * Copyright (c) 2014 Gabriele Mazzotta <gabriele.mzt@gmail.com>
6 * Copyright (c) 2014 Pali Rohár <pali.rohar@gmail.com>
7 * Copyright (c) 2017 Dell Inc.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14
15#include <linux/dmi.h>
16#include <linux/gfp.h>
17#include <linux/io.h>
18#include <linux/module.h>
19#include <linux/mutex.h>
20#include <linux/platform_device.h>
21#include "../../firmware/dcdbas.h"
22#include "dell-smbios.h"
23
24static int da_command_address;
25static int da_command_code;
26static struct calling_interface_buffer *buffer;
27struct platform_device *platform_device;
28static DEFINE_MUTEX(smm_mutex);
29
30static const struct dmi_system_id dell_device_table[] __initconst = {
31 {
32 .ident = "Dell laptop",
33 .matches = {
34 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
35 DMI_MATCH(DMI_CHASSIS_TYPE, "8"),
36 },
37 },
38 {
39 .matches = {
40 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
41 DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /*Laptop*/
42 },
43 },
44 {
45 .matches = {
46 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
47 DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /*Notebook*/
48 },
49 },
50 {
51 .ident = "Dell Computer Corporation",
52 .matches = {
53 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
54 DMI_MATCH(DMI_CHASSIS_TYPE, "8"),
55 },
56 },
57 { }
58};
59MODULE_DEVICE_TABLE(dmi, dell_device_table);
60
61static void __init parse_da_table(const struct dmi_header *dm)
62{
63 struct calling_interface_structure *table =
64 container_of(dm, struct calling_interface_structure, header);
65
66 /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least
67 * 6 bytes of entry
68 */
69 if (dm->length < 17)
70 return;
71
72 da_command_address = table->cmdIOAddress;
73 da_command_code = table->cmdIOCode;
74}
75
76static void __init find_cmd_address(const struct dmi_header *dm, void *dummy)
77{
78 switch (dm->type) {
79 case 0xda: /* Calling interface */
80 parse_da_table(dm);
81 break;
82 }
83}
84
85int dell_smbios_smm_call(struct calling_interface_buffer *input)
86{
87 struct smi_cmd command;
88 size_t size;
89
90 size = sizeof(struct calling_interface_buffer);
91 command.magic = SMI_CMD_MAGIC;
92 command.command_address = da_command_address;
93 command.command_code = da_command_code;
94 command.ebx = virt_to_phys(buffer);
95 command.ecx = 0x42534931;
96
97 mutex_lock(&smm_mutex);
98 memcpy(buffer, input, size);
99 dcdbas_smi_request(&command);
100 memcpy(input, buffer, size);
101 mutex_unlock(&smm_mutex);
102 return 0;
103}
104
105/* When enabled this indicates that SMM won't work */
106static bool test_wsmt_enabled(void)
107{
108 struct calling_interface_token *wsmt;
109
110 /* if token doesn't exist, SMM will work */
111 wsmt = dell_smbios_find_token(WSMT_EN_TOKEN);
112 if (!wsmt)
113 return false;
114
115 /* If token exists, try to access over SMM but set a dummy return.
116 * - If WSMT disabled it will be overwritten by SMM
117 * - If WSMT enabled then dummy value will remain
118 */
119 buffer->cmd_class = CLASS_TOKEN_READ;
120 buffer->cmd_select = SELECT_TOKEN_STD;
121 memset(buffer, 0, sizeof(struct calling_interface_buffer));
122 buffer->input[0] = wsmt->location;
123 buffer->output[0] = 99;
124 dell_smbios_smm_call(buffer);
125 if (buffer->output[0] == 99)
126 return true;
127
128 return false;
129}
130
131static int __init dell_smbios_smm_init(void)
132{
133 int ret;
134 /*
135 * Allocate buffer below 4GB for SMI data--only 32-bit physical addr
136 * is passed to SMI handler.
137 */
138 buffer = (void *)__get_free_page(GFP_KERNEL | GFP_DMA32);
139 if (!buffer)
140 return -ENOMEM;
141
142 dmi_walk(find_cmd_address, NULL);
143
144 if (test_wsmt_enabled()) {
145 pr_debug("Disabling due to WSMT enabled\n");
146 ret = -ENODEV;
147 goto fail_wsmt;
148 }
149
150 platform_device = platform_device_alloc("dell-smbios", 1);
151 if (!platform_device) {
152 ret = -ENOMEM;
153 goto fail_platform_device_alloc;
154 }
155
156 ret = platform_device_add(platform_device);
157 if (ret)
158 goto fail_platform_device_add;
159
160 ret = dell_smbios_register_device(&platform_device->dev,
161 &dell_smbios_smm_call);
162 if (ret)
163 goto fail_register;
164
165 return 0;
166
167fail_register:
168 platform_device_del(platform_device);
169
170fail_platform_device_add:
171 platform_device_put(platform_device);
172
173fail_wsmt:
174fail_platform_device_alloc:
175 free_page((unsigned long)buffer);
176 return ret;
177}
178
179static void __exit dell_smbios_smm_exit(void)
180{
181 if (platform_device) {
182 dell_smbios_unregister_device(&platform_device->dev);
183 platform_device_unregister(platform_device);
184 free_page((unsigned long)buffer);
185 }
186}
187
188subsys_initcall(dell_smbios_smm_init);
189module_exit(dell_smbios_smm_exit);
190
191MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
192MODULE_AUTHOR("Gabriele Mazzotta <gabriele.mzt@gmail.com>");
193MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
194MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
195MODULE_DESCRIPTION("Dell SMBIOS communications over SMI");
196MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/dell-smbios-wmi.c b/drivers/platform/x86/dell-smbios-wmi.c
new file mode 100644
index 000000000000..0cab1f9c35af
--- /dev/null
+++ b/drivers/platform/x86/dell-smbios-wmi.c
@@ -0,0 +1,272 @@
1/*
2 * WMI methods for use with dell-smbios
3 *
4 * Copyright (c) 2017 Dell Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11
12#include <linux/dmi.h>
13#include <linux/list.h>
14#include <linux/module.h>
15#include <linux/mutex.h>
16#include <linux/uaccess.h>
17#include <linux/wmi.h>
18#include "dell-smbios.h"
19#include "dell-wmi-descriptor.h"
20
21static DEFINE_MUTEX(call_mutex);
22static DEFINE_MUTEX(list_mutex);
23static int wmi_supported;
24
25struct misc_bios_flags_structure {
26 struct dmi_header header;
27 u16 flags0;
28} __packed;
29#define FLAG_HAS_ACPI_WMI 0x02
30
31#define DELL_WMI_SMBIOS_GUID "A80593CE-A997-11DA-B012-B622A1EF5492"
32
33struct wmi_smbios_priv {
34 struct dell_wmi_smbios_buffer *buf;
35 struct list_head list;
36 struct wmi_device *wdev;
37 struct device *child;
38 u32 req_buf_size;
39};
40static LIST_HEAD(wmi_list);
41
42static inline struct wmi_smbios_priv *get_first_smbios_priv(void)
43{
44 return list_first_entry_or_null(&wmi_list,
45 struct wmi_smbios_priv,
46 list);
47}
48
49static int run_smbios_call(struct wmi_device *wdev)
50{
51 struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
52 struct wmi_smbios_priv *priv;
53 struct acpi_buffer input;
54 union acpi_object *obj;
55 acpi_status status;
56
57 priv = dev_get_drvdata(&wdev->dev);
58 input.length = priv->req_buf_size - sizeof(u64);
59 input.pointer = &priv->buf->std;
60
61 dev_dbg(&wdev->dev, "evaluating: %u/%u [%x,%x,%x,%x]\n",
62 priv->buf->std.cmd_class, priv->buf->std.cmd_select,
63 priv->buf->std.input[0], priv->buf->std.input[1],
64 priv->buf->std.input[2], priv->buf->std.input[3]);
65
66 status = wmidev_evaluate_method(wdev, 0, 1, &input, &output);
67 if (ACPI_FAILURE(status))
68 return -EIO;
69 obj = (union acpi_object *)output.pointer;
70 if (obj->type != ACPI_TYPE_BUFFER) {
71 dev_dbg(&wdev->dev, "received type: %d\n", obj->type);
72 if (obj->type == ACPI_TYPE_INTEGER)
73 dev_dbg(&wdev->dev, "SMBIOS call failed: %llu\n",
74 obj->integer.value);
75 return -EIO;
76 }
77 memcpy(&priv->buf->std, obj->buffer.pointer, obj->buffer.length);
78 dev_dbg(&wdev->dev, "result: [%08x,%08x,%08x,%08x]\n",
79 priv->buf->std.output[0], priv->buf->std.output[1],
80 priv->buf->std.output[2], priv->buf->std.output[3]);
81
82 return 0;
83}
84
85int dell_smbios_wmi_call(struct calling_interface_buffer *buffer)
86{
87 struct wmi_smbios_priv *priv;
88 size_t difference;
89 size_t size;
90 int ret;
91
92 mutex_lock(&call_mutex);
93 priv = get_first_smbios_priv();
94 if (!priv) {
95 ret = -ENODEV;
96 goto out_wmi_call;
97 }
98
99 size = sizeof(struct calling_interface_buffer);
100 difference = priv->req_buf_size - sizeof(u64) - size;
101
102 memset(&priv->buf->ext, 0, difference);
103 memcpy(&priv->buf->std, buffer, size);
104 ret = run_smbios_call(priv->wdev);
105 memcpy(buffer, &priv->buf->std, size);
106out_wmi_call:
107 mutex_unlock(&call_mutex);
108
109 return ret;
110}
111
112static long dell_smbios_wmi_filter(struct wmi_device *wdev, unsigned int cmd,
113 struct wmi_ioctl_buffer *arg)
114{
115 struct wmi_smbios_priv *priv;
116 int ret = 0;
117
118 switch (cmd) {
119 case DELL_WMI_SMBIOS_CMD:
120 mutex_lock(&call_mutex);
121 priv = dev_get_drvdata(&wdev->dev);
122 if (!priv) {
123 ret = -ENODEV;
124 goto fail_smbios_cmd;
125 }
126 memcpy(priv->buf, arg, priv->req_buf_size);
127 if (dell_smbios_call_filter(&wdev->dev, &priv->buf->std)) {
128 dev_err(&wdev->dev, "Invalid call %d/%d:%8x\n",
129 priv->buf->std.cmd_class,
130 priv->buf->std.cmd_select,
131 priv->buf->std.input[0]);
132 ret = -EFAULT;
133 goto fail_smbios_cmd;
134 }
135 ret = run_smbios_call(priv->wdev);
136 if (ret)
137 goto fail_smbios_cmd;
138 memcpy(arg, priv->buf, priv->req_buf_size);
139fail_smbios_cmd:
140 mutex_unlock(&call_mutex);
141 break;
142 default:
143 ret = -ENOIOCTLCMD;
144 }
145 return ret;
146}
147
148static int dell_smbios_wmi_probe(struct wmi_device *wdev)
149{
150 struct wmi_smbios_priv *priv;
151 int count;
152 int ret;
153
154 ret = dell_wmi_get_descriptor_valid();
155 if (ret)
156 return ret;
157
158 priv = devm_kzalloc(&wdev->dev, sizeof(struct wmi_smbios_priv),
159 GFP_KERNEL);
160 if (!priv)
161 return -ENOMEM;
162
163 /* WMI buffer size will be either 4k or 32k depending on machine */
164 if (!dell_wmi_get_size(&priv->req_buf_size))
165 return -EPROBE_DEFER;
166
167 /* add in the length object we will use internally with ioctl */
168 priv->req_buf_size += sizeof(u64);
169 ret = set_required_buffer_size(wdev, priv->req_buf_size);
170 if (ret)
171 return ret;
172
173 count = get_order(priv->req_buf_size);
174 priv->buf = (void *)__get_free_pages(GFP_KERNEL, count);
175 if (!priv->buf)
176 return -ENOMEM;
177
178 /* ID is used by dell-smbios to set priority of drivers */
179 wdev->dev.id = 1;
180 ret = dell_smbios_register_device(&wdev->dev, &dell_smbios_wmi_call);
181 if (ret)
182 goto fail_register;
183
184 priv->wdev = wdev;
185 dev_set_drvdata(&wdev->dev, priv);
186 mutex_lock(&list_mutex);
187 list_add_tail(&priv->list, &wmi_list);
188 mutex_unlock(&list_mutex);
189
190 return 0;
191
192fail_register:
193 free_pages((unsigned long)priv->buf, count);
194 return ret;
195}
196
197static int dell_smbios_wmi_remove(struct wmi_device *wdev)
198{
199 struct wmi_smbios_priv *priv = dev_get_drvdata(&wdev->dev);
200 int count;
201
202 mutex_lock(&call_mutex);
203 mutex_lock(&list_mutex);
204 list_del(&priv->list);
205 mutex_unlock(&list_mutex);
206 dell_smbios_unregister_device(&wdev->dev);
207 count = get_order(priv->req_buf_size);
208 free_pages((unsigned long)priv->buf, count);
209 mutex_unlock(&call_mutex);
210 return 0;
211}
212
213static const struct wmi_device_id dell_smbios_wmi_id_table[] = {
214 { .guid_string = DELL_WMI_SMBIOS_GUID },
215 { },
216};
217
218static void __init parse_b1_table(const struct dmi_header *dm)
219{
220 struct misc_bios_flags_structure *flags =
221 container_of(dm, struct misc_bios_flags_structure, header);
222
223 /* 4 bytes header, 8 bytes flags */
224 if (dm->length < 12)
225 return;
226 if (dm->handle != 0xb100)
227 return;
228 if ((flags->flags0 & FLAG_HAS_ACPI_WMI))
229 wmi_supported = 1;
230}
231
232static void __init find_b1(const struct dmi_header *dm, void *dummy)
233{
234 switch (dm->type) {
235 case 0xb1: /* misc bios flags */
236 parse_b1_table(dm);
237 break;
238 }
239}
240
241static struct wmi_driver dell_smbios_wmi_driver = {
242 .driver = {
243 .name = "dell-smbios",
244 },
245 .probe = dell_smbios_wmi_probe,
246 .remove = dell_smbios_wmi_remove,
247 .id_table = dell_smbios_wmi_id_table,
248 .filter_callback = dell_smbios_wmi_filter,
249};
250
251static int __init init_dell_smbios_wmi(void)
252{
253 dmi_walk(find_b1, NULL);
254
255 if (!wmi_supported)
256 return -ENODEV;
257
258 return wmi_driver_register(&dell_smbios_wmi_driver);
259}
260
261static void __exit exit_dell_smbios_wmi(void)
262{
263 wmi_driver_unregister(&dell_smbios_wmi_driver);
264}
265
266module_init(init_dell_smbios_wmi);
267module_exit(exit_dell_smbios_wmi);
268
269MODULE_ALIAS("wmi:" DELL_WMI_SMBIOS_GUID);
270MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
271MODULE_DESCRIPTION("Dell SMBIOS communications over WMI");
272MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c
index 0a5723468bff..6a60db515bda 100644
--- a/drivers/platform/x86/dell-smbios.c
+++ b/drivers/platform/x86/dell-smbios.c
@@ -12,33 +12,119 @@
12 * it under the terms of the GNU General Public License version 2 as 12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation. 13 * published by the Free Software Foundation.
14 */ 14 */
15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15 16
16#include <linux/kernel.h> 17#include <linux/kernel.h>
17#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/capability.h>
18#include <linux/dmi.h> 20#include <linux/dmi.h>
19#include <linux/err.h> 21#include <linux/err.h>
20#include <linux/gfp.h>
21#include <linux/mutex.h> 22#include <linux/mutex.h>
23#include <linux/platform_device.h>
22#include <linux/slab.h> 24#include <linux/slab.h>
23#include <linux/io.h>
24#include "../../firmware/dcdbas.h"
25#include "dell-smbios.h" 25#include "dell-smbios.h"
26 26
27struct calling_interface_structure { 27static u32 da_supported_commands;
28 struct dmi_header header;
29 u16 cmdIOAddress;
30 u8 cmdIOCode;
31 u32 supportedCmds;
32 struct calling_interface_token tokens[];
33} __packed;
34
35static struct calling_interface_buffer *buffer;
36static DEFINE_MUTEX(buffer_mutex);
37
38static int da_command_address;
39static int da_command_code;
40static int da_num_tokens; 28static int da_num_tokens;
29static struct platform_device *platform_device;
41static struct calling_interface_token *da_tokens; 30static struct calling_interface_token *da_tokens;
31static struct device_attribute *token_location_attrs;
32static struct device_attribute *token_value_attrs;
33static struct attribute **token_attrs;
34static DEFINE_MUTEX(smbios_mutex);
35
36struct smbios_device {
37 struct list_head list;
38 struct device *device;
39 int (*call_fn)(struct calling_interface_buffer *);
40};
41
42struct smbios_call {
43 u32 need_capability;
44 int cmd_class;
45 int cmd_select;
46};
47
48/* calls that are whitelisted for given capabilities */
49static struct smbios_call call_whitelist[] = {
50 /* generally tokens are allowed, but may be further filtered or
51 * restricted by token blacklist or whitelist
52 */
53 {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_STD},
54 {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_AC},
55 {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_BAT},
56 {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD},
57 {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_AC},
58 {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT},
59 /* used by userspace: fwupdate */
60 {CAP_SYS_ADMIN, CLASS_ADMIN_PROP, SELECT_ADMIN_PROP},
61 /* used by userspace: fwupd */
62 {CAP_SYS_ADMIN, CLASS_INFO, SELECT_DOCK},
63 {CAP_SYS_ADMIN, CLASS_FLASH_INTERFACE, SELECT_FLASH_INTERFACE},
64};
65
66/* calls that are explicitly blacklisted */
67static struct smbios_call call_blacklist[] = {
68 {0x0000, 01, 07}, /* manufacturing use */
69 {0x0000, 06, 05}, /* manufacturing use */
70 {0x0000, 11, 03}, /* write once */
71 {0x0000, 11, 07}, /* write once */
72 {0x0000, 11, 11}, /* write once */
73 {0x0000, 19, -1}, /* diagnostics */
74 /* handled by kernel: dell-laptop */
75 {0x0000, CLASS_INFO, SELECT_RFKILL},
76 {0x0000, CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT},
77};
78
79struct token_range {
80 u32 need_capability;
81 u16 min;
82 u16 max;
83};
84
85/* tokens that are whitelisted for given capabilities */
86static struct token_range token_whitelist[] = {
87 /* used by userspace: fwupdate */
88 {CAP_SYS_ADMIN, CAPSULE_EN_TOKEN, CAPSULE_DIS_TOKEN},
89 /* can indicate to userspace that WMI is needed */
90 {0x0000, WSMT_EN_TOKEN, WSMT_DIS_TOKEN}
91};
92
93/* tokens that are explicitly blacklisted */
94static struct token_range token_blacklist[] = {
95 {0x0000, 0x0058, 0x0059}, /* ME use */
96 {0x0000, 0x00CD, 0x00D0}, /* raid shadow copy */
97 {0x0000, 0x013A, 0x01FF}, /* sata shadow copy */
98 {0x0000, 0x0175, 0x0176}, /* write once */
99 {0x0000, 0x0195, 0x0197}, /* diagnostics */
100 {0x0000, 0x01DC, 0x01DD}, /* manufacturing use */
101 {0x0000, 0x027D, 0x0284}, /* diagnostics */
102 {0x0000, 0x02E3, 0x02E3}, /* manufacturing use */
103 {0x0000, 0x02FF, 0x02FF}, /* manufacturing use */
104 {0x0000, 0x0300, 0x0302}, /* manufacturing use */
105 {0x0000, 0x0325, 0x0326}, /* manufacturing use */
106 {0x0000, 0x0332, 0x0335}, /* fan control */
107 {0x0000, 0x0350, 0x0350}, /* manufacturing use */
108 {0x0000, 0x0363, 0x0363}, /* manufacturing use */
109 {0x0000, 0x0368, 0x0368}, /* manufacturing use */
110 {0x0000, 0x03F6, 0x03F7}, /* manufacturing use */
111 {0x0000, 0x049E, 0x049F}, /* manufacturing use */
112 {0x0000, 0x04A0, 0x04A3}, /* disagnostics */
113 {0x0000, 0x04E6, 0x04E7}, /* manufacturing use */
114 {0x0000, 0x4000, 0x7FFF}, /* internal BIOS use */
115 {0x0000, 0x9000, 0x9001}, /* internal BIOS use */
116 {0x0000, 0xA000, 0xBFFF}, /* write only */
117 {0x0000, 0xEFF0, 0xEFFF}, /* internal BIOS use */
118 /* handled by kernel: dell-laptop */
119 {0x0000, BRIGHTNESS_TOKEN, BRIGHTNESS_TOKEN},
120 {0x0000, KBD_LED_OFF_TOKEN, KBD_LED_AUTO_TOKEN},
121 {0x0000, KBD_LED_AC_TOKEN, KBD_LED_AC_TOKEN},
122 {0x0000, KBD_LED_AUTO_25_TOKEN, KBD_LED_AUTO_75_TOKEN},
123 {0x0000, KBD_LED_AUTO_100_TOKEN, KBD_LED_AUTO_100_TOKEN},
124 {0x0000, GLOBAL_MIC_MUTE_ENABLE, GLOBAL_MIC_MUTE_DISABLE},
125};
126
127static LIST_HEAD(smbios_device_list);
42 128
43int dell_smbios_error(int value) 129int dell_smbios_error(int value)
44{ 130{
@@ -55,42 +141,175 @@ int dell_smbios_error(int value)
55} 141}
56EXPORT_SYMBOL_GPL(dell_smbios_error); 142EXPORT_SYMBOL_GPL(dell_smbios_error);
57 143
58struct calling_interface_buffer *dell_smbios_get_buffer(void) 144int dell_smbios_register_device(struct device *d, void *call_fn)
59{ 145{
60 mutex_lock(&buffer_mutex); 146 struct smbios_device *priv;
61 dell_smbios_clear_buffer(); 147
62 return buffer; 148 priv = devm_kzalloc(d, sizeof(struct smbios_device), GFP_KERNEL);
149 if (!priv)
150 return -ENOMEM;
151 get_device(d);
152 priv->device = d;
153 priv->call_fn = call_fn;
154 mutex_lock(&smbios_mutex);
155 list_add_tail(&priv->list, &smbios_device_list);
156 mutex_unlock(&smbios_mutex);
157 dev_dbg(d, "Added device: %s\n", d->driver->name);
158 return 0;
63} 159}
64EXPORT_SYMBOL_GPL(dell_smbios_get_buffer); 160EXPORT_SYMBOL_GPL(dell_smbios_register_device);
65 161
66void dell_smbios_clear_buffer(void) 162void dell_smbios_unregister_device(struct device *d)
67{ 163{
68 memset(buffer, 0, sizeof(struct calling_interface_buffer)); 164 struct smbios_device *priv;
165
166 mutex_lock(&smbios_mutex);
167 list_for_each_entry(priv, &smbios_device_list, list) {
168 if (priv->device == d) {
169 list_del(&priv->list);
170 put_device(d);
171 break;
172 }
173 }
174 mutex_unlock(&smbios_mutex);
175 dev_dbg(d, "Remove device: %s\n", d->driver->name);
69} 176}
70EXPORT_SYMBOL_GPL(dell_smbios_clear_buffer); 177EXPORT_SYMBOL_GPL(dell_smbios_unregister_device);
71 178
72void dell_smbios_release_buffer(void) 179int dell_smbios_call_filter(struct device *d,
180 struct calling_interface_buffer *buffer)
73{ 181{
74 mutex_unlock(&buffer_mutex); 182 u16 t = 0;
183 int i;
184
185 /* can't make calls over 30 */
186 if (buffer->cmd_class > 30) {
187 dev_dbg(d, "class too big: %u\n", buffer->cmd_class);
188 return -EINVAL;
189 }
190
191 /* supported calls on the particular system */
192 if (!(da_supported_commands & (1 << buffer->cmd_class))) {
193 dev_dbg(d, "invalid command, supported commands: 0x%8x\n",
194 da_supported_commands);
195 return -EINVAL;
196 }
197
198 /* match against call blacklist */
199 for (i = 0; i < ARRAY_SIZE(call_blacklist); i++) {
200 if (buffer->cmd_class != call_blacklist[i].cmd_class)
201 continue;
202 if (buffer->cmd_select != call_blacklist[i].cmd_select &&
203 call_blacklist[i].cmd_select != -1)
204 continue;
205 dev_dbg(d, "blacklisted command: %u/%u\n",
206 buffer->cmd_class, buffer->cmd_select);
207 return -EINVAL;
208 }
209
210 /* if a token call, find token ID */
211
212 if ((buffer->cmd_class == CLASS_TOKEN_READ ||
213 buffer->cmd_class == CLASS_TOKEN_WRITE) &&
214 buffer->cmd_select < 3) {
215 /* find the matching token ID */
216 for (i = 0; i < da_num_tokens; i++) {
217 if (da_tokens[i].location != buffer->input[0])
218 continue;
219 t = da_tokens[i].tokenID;
220 break;
221 }
222
223 /* token call; but token didn't exist */
224 if (!t) {
225 dev_dbg(d, "token at location %04x doesn't exist\n",
226 buffer->input[0]);
227 return -EINVAL;
228 }
229
230 /* match against token blacklist */
231 for (i = 0; i < ARRAY_SIZE(token_blacklist); i++) {
232 if (!token_blacklist[i].min || !token_blacklist[i].max)
233 continue;
234 if (t >= token_blacklist[i].min &&
235 t <= token_blacklist[i].max)
236 return -EINVAL;
237 }
238
239 /* match against token whitelist */
240 for (i = 0; i < ARRAY_SIZE(token_whitelist); i++) {
241 if (!token_whitelist[i].min || !token_whitelist[i].max)
242 continue;
243 if (t < token_whitelist[i].min ||
244 t > token_whitelist[i].max)
245 continue;
246 if (!token_whitelist[i].need_capability ||
247 capable(token_whitelist[i].need_capability)) {
248 dev_dbg(d, "whitelisted token: %x\n", t);
249 return 0;
250 }
251
252 }
253 }
254 /* match against call whitelist */
255 for (i = 0; i < ARRAY_SIZE(call_whitelist); i++) {
256 if (buffer->cmd_class != call_whitelist[i].cmd_class)
257 continue;
258 if (buffer->cmd_select != call_whitelist[i].cmd_select)
259 continue;
260 if (!call_whitelist[i].need_capability ||
261 capable(call_whitelist[i].need_capability)) {
262 dev_dbg(d, "whitelisted capable command: %u/%u\n",
263 buffer->cmd_class, buffer->cmd_select);
264 return 0;
265 }
266 dev_dbg(d, "missing capability %d for %u/%u\n",
267 call_whitelist[i].need_capability,
268 buffer->cmd_class, buffer->cmd_select);
269
270 }
271
272 /* not in a whitelist, only allow processes with capabilities */
273 if (capable(CAP_SYS_RAWIO)) {
274 dev_dbg(d, "Allowing %u/%u due to CAP_SYS_RAWIO\n",
275 buffer->cmd_class, buffer->cmd_select);
276 return 0;
277 }
278
279 return -EACCES;
75} 280}
76EXPORT_SYMBOL_GPL(dell_smbios_release_buffer); 281EXPORT_SYMBOL_GPL(dell_smbios_call_filter);
77 282
78void dell_smbios_send_request(int class, int select) 283int dell_smbios_call(struct calling_interface_buffer *buffer)
79{ 284{
80 struct smi_cmd command; 285 int (*call_fn)(struct calling_interface_buffer *) = NULL;
286 struct device *selected_dev = NULL;
287 struct smbios_device *priv;
288 int ret;
81 289
82 command.magic = SMI_CMD_MAGIC; 290 mutex_lock(&smbios_mutex);
83 command.command_address = da_command_address; 291 list_for_each_entry(priv, &smbios_device_list, list) {
84 command.command_code = da_command_code; 292 if (!selected_dev || priv->device->id >= selected_dev->id) {
85 command.ebx = virt_to_phys(buffer); 293 dev_dbg(priv->device, "Trying device ID: %d\n",
86 command.ecx = 0x42534931; 294 priv->device->id);
295 call_fn = priv->call_fn;
296 selected_dev = priv->device;
297 }
298 }
299
300 if (!selected_dev) {
301 ret = -ENODEV;
302 pr_err("No dell-smbios drivers are loaded\n");
303 goto out_smbios_call;
304 }
87 305
88 buffer->class = class; 306 ret = call_fn(buffer);
89 buffer->select = select;
90 307
91 dcdbas_smi_request(&command); 308out_smbios_call:
309 mutex_unlock(&smbios_mutex);
310 return ret;
92} 311}
93EXPORT_SYMBOL_GPL(dell_smbios_send_request); 312EXPORT_SYMBOL_GPL(dell_smbios_call);
94 313
95struct calling_interface_token *dell_smbios_find_token(int tokenid) 314struct calling_interface_token *dell_smbios_find_token(int tokenid)
96{ 315{
@@ -139,8 +358,7 @@ static void __init parse_da_table(const struct dmi_header *dm)
139 if (dm->length < 17) 358 if (dm->length < 17)
140 return; 359 return;
141 360
142 da_command_address = table->cmdIOAddress; 361 da_supported_commands = table->supportedCmds;
143 da_command_code = table->cmdIOCode;
144 362
145 new_da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) * 363 new_da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) *
146 sizeof(struct calling_interface_token), 364 sizeof(struct calling_interface_token),
@@ -156,6 +374,27 @@ static void __init parse_da_table(const struct dmi_header *dm)
156 da_num_tokens += tokens; 374 da_num_tokens += tokens;
157} 375}
158 376
377static void zero_duplicates(struct device *dev)
378{
379 int i, j;
380
381 for (i = 0; i < da_num_tokens; i++) {
382 if (da_tokens[i].tokenID == 0)
383 continue;
384 for (j = i+1; j < da_num_tokens; j++) {
385 if (da_tokens[j].tokenID == 0)
386 continue;
387 if (da_tokens[i].tokenID == da_tokens[j].tokenID) {
388 dev_dbg(dev, "Zeroing dup token ID %x(%x/%x)\n",
389 da_tokens[j].tokenID,
390 da_tokens[j].location,
391 da_tokens[j].value);
392 da_tokens[j].tokenID = 0;
393 }
394 }
395 }
396}
397
159static void __init find_tokens(const struct dmi_header *dm, void *dummy) 398static void __init find_tokens(const struct dmi_header *dm, void *dummy)
160{ 399{
161 switch (dm->type) { 400 switch (dm->type) {
@@ -169,10 +408,160 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy)
169 } 408 }
170} 409}
171 410
411static int match_attribute(struct device *dev,
412 struct device_attribute *attr)
413{
414 int i;
415
416 for (i = 0; i < da_num_tokens * 2; i++) {
417 if (!token_attrs[i])
418 continue;
419 if (strcmp(token_attrs[i]->name, attr->attr.name) == 0)
420 return i/2;
421 }
422 dev_dbg(dev, "couldn't match: %s\n", attr->attr.name);
423 return -EINVAL;
424}
425
426static ssize_t location_show(struct device *dev,
427 struct device_attribute *attr, char *buf)
428{
429 int i;
430
431 if (!capable(CAP_SYS_ADMIN))
432 return -EPERM;
433
434 i = match_attribute(dev, attr);
435 if (i > 0)
436 return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].location);
437 return 0;
438}
439
440static ssize_t value_show(struct device *dev,
441 struct device_attribute *attr, char *buf)
442{
443 int i;
444
445 if (!capable(CAP_SYS_ADMIN))
446 return -EPERM;
447
448 i = match_attribute(dev, attr);
449 if (i > 0)
450 return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].value);
451 return 0;
452}
453
454static struct attribute_group smbios_attribute_group = {
455 .name = "tokens"
456};
457
458static struct platform_driver platform_driver = {
459 .driver = {
460 .name = "dell-smbios",
461 },
462};
463
464static int build_tokens_sysfs(struct platform_device *dev)
465{
466 char *location_name;
467 char *value_name;
468 size_t size;
469 int ret;
470 int i, j;
471
472 /* (number of tokens + 1 for null terminated */
473 size = sizeof(struct device_attribute) * (da_num_tokens + 1);
474 token_location_attrs = kzalloc(size, GFP_KERNEL);
475 if (!token_location_attrs)
476 return -ENOMEM;
477 token_value_attrs = kzalloc(size, GFP_KERNEL);
478 if (!token_value_attrs)
479 goto out_allocate_value;
480
481 /* need to store both location and value + terminator*/
482 size = sizeof(struct attribute *) * ((2 * da_num_tokens) + 1);
483 token_attrs = kzalloc(size, GFP_KERNEL);
484 if (!token_attrs)
485 goto out_allocate_attrs;
486
487 for (i = 0, j = 0; i < da_num_tokens; i++) {
488 /* skip empty */
489 if (da_tokens[i].tokenID == 0)
490 continue;
491 /* add location */
492 location_name = kasprintf(GFP_KERNEL, "%04x_location",
493 da_tokens[i].tokenID);
494 if (location_name == NULL)
495 goto out_unwind_strings;
496 sysfs_attr_init(&token_location_attrs[i].attr);
497 token_location_attrs[i].attr.name = location_name;
498 token_location_attrs[i].attr.mode = 0444;
499 token_location_attrs[i].show = location_show;
500 token_attrs[j++] = &token_location_attrs[i].attr;
501
502 /* add value */
503 value_name = kasprintf(GFP_KERNEL, "%04x_value",
504 da_tokens[i].tokenID);
505 if (value_name == NULL)
506 goto loop_fail_create_value;
507 sysfs_attr_init(&token_value_attrs[i].attr);
508 token_value_attrs[i].attr.name = value_name;
509 token_value_attrs[i].attr.mode = 0444;
510 token_value_attrs[i].show = value_show;
511 token_attrs[j++] = &token_value_attrs[i].attr;
512 continue;
513
514loop_fail_create_value:
515 kfree(value_name);
516 goto out_unwind_strings;
517 }
518 smbios_attribute_group.attrs = token_attrs;
519
520 ret = sysfs_create_group(&dev->dev.kobj, &smbios_attribute_group);
521 if (ret)
522 goto out_unwind_strings;
523 return 0;
524
525out_unwind_strings:
526 for (i = i-1; i > 0; i--) {
527 kfree(token_location_attrs[i].attr.name);
528 kfree(token_value_attrs[i].attr.name);
529 }
530 kfree(token_attrs);
531out_allocate_attrs:
532 kfree(token_value_attrs);
533out_allocate_value:
534 kfree(token_location_attrs);
535
536 return -ENOMEM;
537}
538
539static void free_group(struct platform_device *pdev)
540{
541 int i;
542
543 sysfs_remove_group(&pdev->dev.kobj,
544 &smbios_attribute_group);
545 for (i = 0; i < da_num_tokens; i++) {
546 kfree(token_location_attrs[i].attr.name);
547 kfree(token_value_attrs[i].attr.name);
548 }
549 kfree(token_attrs);
550 kfree(token_value_attrs);
551 kfree(token_location_attrs);
552}
553
172static int __init dell_smbios_init(void) 554static int __init dell_smbios_init(void)
173{ 555{
556 const struct dmi_device *valid;
174 int ret; 557 int ret;
175 558
559 valid = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL);
560 if (!valid) {
561 pr_err("Unable to run on non-Dell system\n");
562 return -ENODEV;
563 }
564
176 dmi_walk(find_tokens, NULL); 565 dmi_walk(find_tokens, NULL);
177 566
178 if (!da_tokens) { 567 if (!da_tokens) {
@@ -180,27 +569,52 @@ static int __init dell_smbios_init(void)
180 return -ENODEV; 569 return -ENODEV;
181 } 570 }
182 571
183 /* 572 ret = platform_driver_register(&platform_driver);
184 * Allocate buffer below 4GB for SMI data--only 32-bit physical addr 573 if (ret)
185 * is passed to SMI handler. 574 goto fail_platform_driver;
186 */ 575
187 buffer = (void *)__get_free_page(GFP_KERNEL | GFP_DMA32); 576 platform_device = platform_device_alloc("dell-smbios", 0);
188 if (!buffer) { 577 if (!platform_device) {
189 ret = -ENOMEM; 578 ret = -ENOMEM;
190 goto fail_buffer; 579 goto fail_platform_device_alloc;
191 } 580 }
581 ret = platform_device_add(platform_device);
582 if (ret)
583 goto fail_platform_device_add;
584
585 /* duplicate tokens will cause problems building sysfs files */
586 zero_duplicates(&platform_device->dev);
587
588 ret = build_tokens_sysfs(platform_device);
589 if (ret)
590 goto fail_create_group;
192 591
193 return 0; 592 return 0;
194 593
195fail_buffer: 594fail_create_group:
595 platform_device_del(platform_device);
596
597fail_platform_device_add:
598 platform_device_put(platform_device);
599
600fail_platform_device_alloc:
601 platform_driver_unregister(&platform_driver);
602
603fail_platform_driver:
196 kfree(da_tokens); 604 kfree(da_tokens);
197 return ret; 605 return ret;
198} 606}
199 607
200static void __exit dell_smbios_exit(void) 608static void __exit dell_smbios_exit(void)
201{ 609{
610 mutex_lock(&smbios_mutex);
611 if (platform_device) {
612 free_group(platform_device);
613 platform_device_unregister(platform_device);
614 platform_driver_unregister(&platform_driver);
615 }
202 kfree(da_tokens); 616 kfree(da_tokens);
203 free_page((unsigned long)buffer); 617 mutex_unlock(&smbios_mutex);
204} 618}
205 619
206subsys_initcall(dell_smbios_init); 620subsys_initcall(dell_smbios_init);
diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h
index 45cbc2292cd3..138d478d9adc 100644
--- a/drivers/platform/x86/dell-smbios.h
+++ b/drivers/platform/x86/dell-smbios.h
@@ -16,17 +16,29 @@
16#ifndef _DELL_SMBIOS_H_ 16#ifndef _DELL_SMBIOS_H_
17#define _DELL_SMBIOS_H_ 17#define _DELL_SMBIOS_H_
18 18
19struct notifier_block; 19#include <linux/device.h>
20#include <uapi/linux/wmi.h>
20 21
21/* This structure will be modified by the firmware when we enter 22/* Classes and selects used only in kernel drivers */
22 * system management mode, hence the volatiles */ 23#define CLASS_KBD_BACKLIGHT 4
24#define SELECT_KBD_BACKLIGHT 11
23 25
24struct calling_interface_buffer { 26/* Tokens used in kernel drivers, any of these
25 u16 class; 27 * should be filtered from userspace access
26 u16 select; 28 */
27 volatile u32 input[4]; 29#define BRIGHTNESS_TOKEN 0x007d
28 volatile u32 output[4]; 30#define KBD_LED_AC_TOKEN 0x0451
29} __packed; 31#define KBD_LED_OFF_TOKEN 0x01E1
32#define KBD_LED_ON_TOKEN 0x01E2
33#define KBD_LED_AUTO_TOKEN 0x01E3
34#define KBD_LED_AUTO_25_TOKEN 0x02EA
35#define KBD_LED_AUTO_50_TOKEN 0x02EB
36#define KBD_LED_AUTO_75_TOKEN 0x02EC
37#define KBD_LED_AUTO_100_TOKEN 0x02F6
38#define GLOBAL_MIC_MUTE_ENABLE 0x0364
39#define GLOBAL_MIC_MUTE_DISABLE 0x0365
40
41struct notifier_block;
30 42
31struct calling_interface_token { 43struct calling_interface_token {
32 u16 tokenID; 44 u16 tokenID;
@@ -37,12 +49,21 @@ struct calling_interface_token {
37 }; 49 };
38}; 50};
39 51
40int dell_smbios_error(int value); 52struct calling_interface_structure {
53 struct dmi_header header;
54 u16 cmdIOAddress;
55 u8 cmdIOCode;
56 u32 supportedCmds;
57 struct calling_interface_token tokens[];
58} __packed;
41 59
42struct calling_interface_buffer *dell_smbios_get_buffer(void); 60int dell_smbios_register_device(struct device *d, void *call_fn);
43void dell_smbios_clear_buffer(void); 61void dell_smbios_unregister_device(struct device *d);
44void dell_smbios_release_buffer(void); 62
45void dell_smbios_send_request(int class, int select); 63int dell_smbios_error(int value);
64int dell_smbios_call_filter(struct device *d,
65 struct calling_interface_buffer *buffer);
66int dell_smbios_call(struct calling_interface_buffer *buffer);
46 67
47struct calling_interface_token *dell_smbios_find_token(int tokenid); 68struct calling_interface_token *dell_smbios_find_token(int tokenid);
48 69
diff --git a/drivers/platform/x86/dell-smo8800.c b/drivers/platform/x86/dell-smo8800.c
index 37e646034ef8..1d87237bc731 100644
--- a/drivers/platform/x86/dell-smo8800.c
+++ b/drivers/platform/x86/dell-smo8800.c
@@ -90,7 +90,7 @@ static ssize_t smo8800_misc_read(struct file *file, char __user *buf,
90 struct smo8800_device, miscdev); 90 struct smo8800_device, miscdev);
91 91
92 u32 data = 0; 92 u32 data = 0;
93 unsigned char byte_data = 0; 93 unsigned char byte_data;
94 ssize_t retval = 1; 94 ssize_t retval = 1;
95 95
96 if (count < 1) 96 if (count < 1)
@@ -103,7 +103,6 @@ static ssize_t smo8800_misc_read(struct file *file, char __user *buf,
103 if (retval) 103 if (retval)
104 return retval; 104 return retval;
105 105
106 byte_data = 1;
107 retval = 1; 106 retval = 1;
108 107
109 if (data < 255) 108 if (data < 255)
diff --git a/drivers/platform/x86/dell-wmi-descriptor.c b/drivers/platform/x86/dell-wmi-descriptor.c
new file mode 100644
index 000000000000..4dfef1f53481
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-descriptor.c
@@ -0,0 +1,191 @@
1/*
2 * Dell WMI descriptor driver
3 *
4 * Copyright (C) 2017 Dell Inc. All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17
18#include <linux/acpi.h>
19#include <linux/list.h>
20#include <linux/module.h>
21#include <linux/wmi.h>
22#include "dell-wmi-descriptor.h"
23
24#define DELL_WMI_DESCRIPTOR_GUID "8D9DDCBC-A997-11DA-B012-B622A1EF5492"
25
26struct descriptor_priv {
27 struct list_head list;
28 u32 interface_version;
29 u32 size;
30};
31static int descriptor_valid = -EPROBE_DEFER;
32static LIST_HEAD(wmi_list);
33static DEFINE_MUTEX(list_mutex);
34
35int dell_wmi_get_descriptor_valid(void)
36{
37 if (!wmi_has_guid(DELL_WMI_DESCRIPTOR_GUID))
38 return -ENODEV;
39
40 return descriptor_valid;
41}
42EXPORT_SYMBOL_GPL(dell_wmi_get_descriptor_valid);
43
44bool dell_wmi_get_interface_version(u32 *version)
45{
46 struct descriptor_priv *priv;
47 bool ret = false;
48
49 mutex_lock(&list_mutex);
50 priv = list_first_entry_or_null(&wmi_list,
51 struct descriptor_priv,
52 list);
53 if (priv) {
54 *version = priv->interface_version;
55 ret = true;
56 }
57 mutex_unlock(&list_mutex);
58 return ret;
59}
60EXPORT_SYMBOL_GPL(dell_wmi_get_interface_version);
61
62bool dell_wmi_get_size(u32 *size)
63{
64 struct descriptor_priv *priv;
65 bool ret = false;
66
67 mutex_lock(&list_mutex);
68 priv = list_first_entry_or_null(&wmi_list,
69 struct descriptor_priv,
70 list);
71 if (priv) {
72 *size = priv->size;
73 ret = true;
74 }
75 mutex_unlock(&list_mutex);
76 return ret;
77}
78EXPORT_SYMBOL_GPL(dell_wmi_get_size);
79
80/*
81 * Descriptor buffer is 128 byte long and contains:
82 *
83 * Name Offset Length Value
84 * Vendor Signature 0 4 "DELL"
85 * Object Signature 4 4 " WMI"
86 * WMI Interface Version 8 4 <version>
87 * WMI buffer length 12 4 <length>
88 */
89static int dell_wmi_descriptor_probe(struct wmi_device *wdev)
90{
91 union acpi_object *obj = NULL;
92 struct descriptor_priv *priv;
93 u32 *buffer;
94 int ret;
95
96 obj = wmidev_block_query(wdev, 0);
97 if (!obj) {
98 dev_err(&wdev->dev, "failed to read Dell WMI descriptor\n");
99 ret = -EIO;
100 goto out;
101 }
102
103 if (obj->type != ACPI_TYPE_BUFFER) {
104 dev_err(&wdev->dev, "Dell descriptor has wrong type\n");
105 ret = -EINVAL;
106 descriptor_valid = ret;
107 goto out;
108 }
109
110 /* Although it's not technically a failure, this would lead to
111 * unexpected behavior
112 */
113 if (obj->buffer.length != 128) {
114 dev_err(&wdev->dev,
115 "Dell descriptor buffer has unexpected length (%d)\n",
116 obj->buffer.length);
117 ret = -EINVAL;
118 descriptor_valid = ret;
119 goto out;
120 }
121
122 buffer = (u32 *)obj->buffer.pointer;
123
124 if (strncmp(obj->string.pointer, "DELL WMI", 8) != 0) {
125 dev_err(&wdev->dev, "Dell descriptor buffer has invalid signature (%8ph)\n",
126 buffer);
127 ret = -EINVAL;
128 descriptor_valid = ret;
129 goto out;
130 }
131 descriptor_valid = 0;
132
133 if (buffer[2] != 0 && buffer[2] != 1)
134 dev_warn(&wdev->dev, "Dell descriptor buffer has unknown version (%lu)\n",
135 (unsigned long) buffer[2]);
136
137 priv = devm_kzalloc(&wdev->dev, sizeof(struct descriptor_priv),
138 GFP_KERNEL);
139
140 if (!priv) {
141 ret = -ENOMEM;
142 goto out;
143 }
144
145 priv->interface_version = buffer[2];
146 priv->size = buffer[3];
147 ret = 0;
148 dev_set_drvdata(&wdev->dev, priv);
149 mutex_lock(&list_mutex);
150 list_add_tail(&priv->list, &wmi_list);
151 mutex_unlock(&list_mutex);
152
153 dev_dbg(&wdev->dev, "Detected Dell WMI interface version %lu and buffer size %lu\n",
154 (unsigned long) priv->interface_version,
155 (unsigned long) priv->size);
156
157out:
158 kfree(obj);
159 return ret;
160}
161
162static int dell_wmi_descriptor_remove(struct wmi_device *wdev)
163{
164 struct descriptor_priv *priv = dev_get_drvdata(&wdev->dev);
165
166 mutex_lock(&list_mutex);
167 list_del(&priv->list);
168 mutex_unlock(&list_mutex);
169 return 0;
170}
171
172static const struct wmi_device_id dell_wmi_descriptor_id_table[] = {
173 { .guid_string = DELL_WMI_DESCRIPTOR_GUID },
174 { },
175};
176
177static struct wmi_driver dell_wmi_descriptor_driver = {
178 .driver = {
179 .name = "dell-wmi-descriptor",
180 },
181 .probe = dell_wmi_descriptor_probe,
182 .remove = dell_wmi_descriptor_remove,
183 .id_table = dell_wmi_descriptor_id_table,
184};
185
186module_wmi_driver(dell_wmi_descriptor_driver);
187
188MODULE_ALIAS("wmi:" DELL_WMI_DESCRIPTOR_GUID);
189MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
190MODULE_DESCRIPTION("Dell WMI descriptor driver");
191MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/dell-wmi-descriptor.h b/drivers/platform/x86/dell-wmi-descriptor.h
new file mode 100644
index 000000000000..1e8cb96ffd78
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-descriptor.h
@@ -0,0 +1,27 @@
1/*
2 * Dell WMI descriptor driver
3 *
4 * Copyright (c) 2017 Dell Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#ifndef _DELL_WMI_DESCRIPTOR_H_
12#define _DELL_WMI_DESCRIPTOR_H_
13
14#include <linux/wmi.h>
15
16/* possible return values:
17 * -ENODEV: Descriptor GUID missing from WMI bus
18 * -EPROBE_DEFER: probing for dell-wmi-descriptor not yet run
19 * 0: valid descriptor, successfully probed
20 * < 0: invalid descriptor, don't probe dependent devices
21 */
22int dell_wmi_get_descriptor_valid(void);
23
24bool dell_wmi_get_interface_version(u32 *version);
25bool dell_wmi_get_size(u32 *size);
26
27#endif
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 28d9f8696081..39d2f4518483 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -39,6 +39,7 @@
39#include <linux/wmi.h> 39#include <linux/wmi.h>
40#include <acpi/video.h> 40#include <acpi/video.h>
41#include "dell-smbios.h" 41#include "dell-smbios.h"
42#include "dell-wmi-descriptor.h"
42 43
43MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); 44MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
44MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>"); 45MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
@@ -46,12 +47,10 @@ MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver");
46MODULE_LICENSE("GPL"); 47MODULE_LICENSE("GPL");
47 48
48#define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492" 49#define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492"
49#define DELL_DESCRIPTOR_GUID "8D9DDCBC-A997-11DA-B012-B622A1EF5492"
50 50
51static bool wmi_requires_smbios_request; 51static bool wmi_requires_smbios_request;
52 52
53MODULE_ALIAS("wmi:"DELL_EVENT_GUID); 53MODULE_ALIAS("wmi:"DELL_EVENT_GUID);
54MODULE_ALIAS("wmi:"DELL_DESCRIPTOR_GUID);
55 54
56struct dell_wmi_priv { 55struct dell_wmi_priv {
57 struct input_dev *input_dev; 56 struct input_dev *input_dev;
@@ -619,78 +618,6 @@ static void dell_wmi_input_destroy(struct wmi_device *wdev)
619} 618}
620 619
621/* 620/*
622 * Descriptor buffer is 128 byte long and contains:
623 *
624 * Name Offset Length Value
625 * Vendor Signature 0 4 "DELL"
626 * Object Signature 4 4 " WMI"
627 * WMI Interface Version 8 4 <version>
628 * WMI buffer length 12 4 4096
629 */
630static int dell_wmi_check_descriptor_buffer(struct wmi_device *wdev)
631{
632 struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
633 union acpi_object *obj = NULL;
634 struct wmi_device *desc_dev;
635 u32 *buffer;
636 int ret;
637
638 desc_dev = wmidev_get_other_guid(wdev, DELL_DESCRIPTOR_GUID);
639 if (!desc_dev) {
640 dev_err(&wdev->dev, "Dell WMI descriptor does not exist\n");
641 return -ENODEV;
642 }
643
644 obj = wmidev_block_query(desc_dev, 0);
645 if (!obj) {
646 dev_err(&wdev->dev, "failed to read Dell WMI descriptor\n");
647 ret = -EIO;
648 goto out;
649 }
650
651 if (obj->type != ACPI_TYPE_BUFFER) {
652 dev_err(&wdev->dev, "Dell descriptor has wrong type\n");
653 ret = -EINVAL;
654 goto out;
655 }
656
657 if (obj->buffer.length != 128) {
658 dev_err(&wdev->dev,
659 "Dell descriptor buffer has invalid length (%d)\n",
660 obj->buffer.length);
661 if (obj->buffer.length < 16) {
662 ret = -EINVAL;
663 goto out;
664 }
665 }
666
667 buffer = (u32 *)obj->buffer.pointer;
668
669 if (buffer[0] != 0x4C4C4544 && buffer[1] != 0x494D5720)
670 dev_warn(&wdev->dev, "Dell descriptor buffer has invalid signature (%*ph)\n",
671 8, buffer);
672
673 if (buffer[2] != 0 && buffer[2] != 1)
674 dev_warn(&wdev->dev, "Dell descriptor buffer has unknown version (%d)\n",
675 buffer[2]);
676
677 if (buffer[3] != 4096)
678 dev_warn(&wdev->dev, "Dell descriptor buffer has invalid buffer length (%d)\n",
679 buffer[3]);
680
681 priv->interface_version = buffer[2];
682 ret = 0;
683
684 dev_info(&wdev->dev, "Detected Dell WMI interface version %u\n",
685 priv->interface_version);
686
687out:
688 kfree(obj);
689 put_device(&desc_dev->dev);
690 return ret;
691}
692
693/*
694 * According to Dell SMBIOS documentation: 621 * According to Dell SMBIOS documentation:
695 * 622 *
696 * 17 3 Application Program Registration 623 * 17 3 Application Program Registration
@@ -711,13 +638,16 @@ static int dell_wmi_events_set_enabled(bool enable)
711 struct calling_interface_buffer *buffer; 638 struct calling_interface_buffer *buffer;
712 int ret; 639 int ret;
713 640
714 buffer = dell_smbios_get_buffer(); 641 buffer = kzalloc(sizeof(struct calling_interface_buffer), GFP_KERNEL);
642 buffer->cmd_class = CLASS_INFO;
643 buffer->cmd_select = SELECT_APP_REGISTRATION;
715 buffer->input[0] = 0x10000; 644 buffer->input[0] = 0x10000;
716 buffer->input[1] = 0x51534554; 645 buffer->input[1] = 0x51534554;
717 buffer->input[3] = enable; 646 buffer->input[3] = enable;
718 dell_smbios_send_request(17, 3); 647 ret = dell_smbios_call(buffer);
719 ret = buffer->output[0]; 648 if (ret == 0)
720 dell_smbios_release_buffer(); 649 ret = buffer->output[0];
650 kfree(buffer);
721 651
722 return dell_smbios_error(ret); 652 return dell_smbios_error(ret);
723} 653}
@@ -725,7 +655,11 @@ static int dell_wmi_events_set_enabled(bool enable)
725static int dell_wmi_probe(struct wmi_device *wdev) 655static int dell_wmi_probe(struct wmi_device *wdev)
726{ 656{
727 struct dell_wmi_priv *priv; 657 struct dell_wmi_priv *priv;
728 int err; 658 int ret;
659
660 ret = dell_wmi_get_descriptor_valid();
661 if (ret)
662 return ret;
729 663
730 priv = devm_kzalloc( 664 priv = devm_kzalloc(
731 &wdev->dev, sizeof(struct dell_wmi_priv), GFP_KERNEL); 665 &wdev->dev, sizeof(struct dell_wmi_priv), GFP_KERNEL);
@@ -733,9 +667,8 @@ static int dell_wmi_probe(struct wmi_device *wdev)
733 return -ENOMEM; 667 return -ENOMEM;
734 dev_set_drvdata(&wdev->dev, priv); 668 dev_set_drvdata(&wdev->dev, priv);
735 669
736 err = dell_wmi_check_descriptor_buffer(wdev); 670 if (!dell_wmi_get_interface_version(&priv->interface_version))
737 if (err) 671 return -EPROBE_DEFER;
738 return err;
739 672
740 return dell_wmi_input_setup(wdev); 673 return dell_wmi_input_setup(wdev);
741} 674}
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index 56a8195096a2..2cfbd3fa5136 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -691,6 +691,7 @@ static enum led_brightness eco_led_get(struct led_classdev *cdev)
691 691
692static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) 692static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
693{ 693{
694 struct fujitsu_laptop *priv = acpi_driver_data(device);
694 struct led_classdev *led; 695 struct led_classdev *led;
695 int result; 696 int result;
696 697
@@ -724,12 +725,15 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
724 } 725 }
725 726
726 /* 727 /*
727 * BTNI bit 24 seems to indicate the presence of a radio toggle 728 * Some Fujitsu laptops have a radio toggle button in place of a slide
728 * button in place of a slide switch, and all such machines appear 729 * switch and all such machines appear to also have an RF LED. Based on
729 * to also have an RF LED. Therefore use bit 24 as an indicator 730 * comparing DSDT tables of four Fujitsu Lifebook models (E744, E751,
730 * that an RF LED is present. 731 * S7110, S8420; the first one has a radio toggle button, the other
732 * three have slide switches), bit 17 of flags_supported (the value
733 * returned by method S000 of ACPI device FUJ02E3) seems to indicate
734 * whether given model has a radio toggle button.
731 */ 735 */
732 if (call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) { 736 if (priv->flags_supported & BIT(17)) {
733 led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL); 737 led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
734 if (!led) 738 if (!led)
735 return -ENOMEM; 739 return -ENOMEM;
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index b4ed3dc983d5..b4224389febe 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -297,7 +297,7 @@ static int hp_wmi_hw_state(int mask)
297 if (state < 0) 297 if (state < 0)
298 return state; 298 return state;
299 299
300 return state & 0x1; 300 return !!(state & mask);
301} 301}
302 302
303static int __init hp_wmi_bios_2008_later(void) 303static int __init hp_wmi_bios_2008_later(void)
diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c
index 493d8910a74e..7b12abe86b94 100644
--- a/drivers/platform/x86/hp_accel.c
+++ b/drivers/platform/x86/hp_accel.c
@@ -240,6 +240,7 @@ static const struct dmi_system_id lis3lv02d_dmi_ids[] = {
240 AXIS_DMI_MATCH("HDX18", "HP HDX 18", x_inverted), 240 AXIS_DMI_MATCH("HDX18", "HP HDX 18", x_inverted),
241 AXIS_DMI_MATCH("HPB432x", "HP ProBook 432", xy_rotated_left), 241 AXIS_DMI_MATCH("HPB432x", "HP ProBook 432", xy_rotated_left),
242 AXIS_DMI_MATCH("HPB440G3", "HP ProBook 440 G3", x_inverted_usd), 242 AXIS_DMI_MATCH("HPB440G3", "HP ProBook 440 G3", x_inverted_usd),
243 AXIS_DMI_MATCH("HPB440G4", "HP ProBook 440 G4", x_inverted),
243 AXIS_DMI_MATCH("HPB442x", "HP ProBook 442", xy_rotated_left), 244 AXIS_DMI_MATCH("HPB442x", "HP ProBook 442", xy_rotated_left),
244 AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted), 245 AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted),
245 AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap), 246 AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap),
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index fe98d4ac0df3..53ab4e0f8962 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -1166,6 +1166,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
1166 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 910-13IKB"), 1166 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 910-13IKB"),
1167 }, 1167 },
1168 }, 1168 },
1169 {
1170 .ident = "Lenovo YOGA 920-13IKB",
1171 .matches = {
1172 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1173 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 920-13IKB"),
1174 },
1175 },
1169 {} 1176 {}
1170}; 1177};
1171 1178
diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c
index e34fd70b67af..f470279c4c10 100644
--- a/drivers/platform/x86/intel-hid.c
+++ b/drivers/platform/x86/intel-hid.c
@@ -226,6 +226,24 @@ wakeup:
226 return; 226 return;
227 } 227 }
228 228
229 /*
230 * Needed for suspend to work on some platforms that don't expose
231 * the 5-button array, but still send notifies with power button
232 * event code to this device object on power button actions.
233 *
234 * Report the power button press; catch and ignore the button release.
235 */
236 if (!priv->array) {
237 if (event == 0xce) {
238 input_report_key(priv->input_dev, KEY_POWER, 1);
239 input_sync(priv->input_dev);
240 return;
241 }
242
243 if (event == 0xcf)
244 return;
245 }
246
229 /* 0xC0 is for HID events, other values are for 5 button array */ 247 /* 0xC0 is for HID events, other values are for 5 button array */
230 if (event != 0xc0) { 248 if (event != 0xc0) {
231 if (!priv->array || 249 if (!priv->array ||
diff --git a/drivers/platform/x86/intel-wmi-thunderbolt.c b/drivers/platform/x86/intel-wmi-thunderbolt.c
new file mode 100644
index 000000000000..c2257bd06f18
--- /dev/null
+++ b/drivers/platform/x86/intel-wmi-thunderbolt.c
@@ -0,0 +1,98 @@
1/*
2 * WMI Thunderbolt driver
3 *
4 * Copyright (C) 2017 Dell Inc. All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17
18#include <linux/acpi.h>
19#include <linux/device.h>
20#include <linux/fs.h>
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/string.h>
24#include <linux/sysfs.h>
25#include <linux/types.h>
26#include <linux/wmi.h>
27
28#define INTEL_WMI_THUNDERBOLT_GUID "86CCFD48-205E-4A77-9C48-2021CBEDE341"
29
30static ssize_t force_power_store(struct device *dev,
31 struct device_attribute *attr,
32 const char *buf, size_t count)
33{
34 struct acpi_buffer input;
35 acpi_status status;
36 u8 mode;
37
38 input.length = sizeof(u8);
39 input.pointer = &mode;
40 mode = hex_to_bin(buf[0]);
41 if (mode == 0 || mode == 1) {
42 status = wmi_evaluate_method(INTEL_WMI_THUNDERBOLT_GUID, 0, 1,
43 &input, NULL);
44 if (ACPI_FAILURE(status))
45 return -ENODEV;
46 } else {
47 return -EINVAL;
48 }
49 return count;
50}
51
52static DEVICE_ATTR_WO(force_power);
53
54static struct attribute *tbt_attrs[] = {
55 &dev_attr_force_power.attr,
56 NULL
57};
58
59static const struct attribute_group tbt_attribute_group = {
60 .attrs = tbt_attrs,
61};
62
63static int intel_wmi_thunderbolt_probe(struct wmi_device *wdev)
64{
65 int ret;
66
67 ret = sysfs_create_group(&wdev->dev.kobj, &tbt_attribute_group);
68 kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE);
69 return ret;
70}
71
72static int intel_wmi_thunderbolt_remove(struct wmi_device *wdev)
73{
74 sysfs_remove_group(&wdev->dev.kobj, &tbt_attribute_group);
75 kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE);
76 return 0;
77}
78
79static const struct wmi_device_id intel_wmi_thunderbolt_id_table[] = {
80 { .guid_string = INTEL_WMI_THUNDERBOLT_GUID },
81 { },
82};
83
84static struct wmi_driver intel_wmi_thunderbolt_driver = {
85 .driver = {
86 .name = "intel-wmi-thunderbolt",
87 },
88 .probe = intel_wmi_thunderbolt_probe,
89 .remove = intel_wmi_thunderbolt_remove,
90 .id_table = intel_wmi_thunderbolt_id_table,
91};
92
93module_wmi_driver(intel_wmi_thunderbolt_driver);
94
95MODULE_ALIAS("wmi:" INTEL_WMI_THUNDERBOLT_GUID);
96MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
97MODULE_DESCRIPTION("Intel WMI Thunderbolt force power driver");
98MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c
index da706e2c4232..380ef7ec094f 100644
--- a/drivers/platform/x86/intel_cht_int33fe.c
+++ b/drivers/platform/x86/intel_cht_int33fe.c
@@ -24,6 +24,7 @@
24#include <linux/i2c.h> 24#include <linux/i2c.h>
25#include <linux/interrupt.h> 25#include <linux/interrupt.h>
26#include <linux/module.h> 26#include <linux/module.h>
27#include <linux/regulator/consumer.h>
27#include <linux/slab.h> 28#include <linux/slab.h>
28 29
29#define EXPECTED_PTYPE 4 30#define EXPECTED_PTYPE 4
@@ -34,6 +35,42 @@ struct cht_int33fe_data {
34 struct i2c_client *pi3usb30532; 35 struct i2c_client *pi3usb30532;
35}; 36};
36 37
38/*
39 * Grrr I severly dislike buggy BIOS-es. At least one BIOS enumerates
40 * the max17047 both through the INT33FE ACPI device (it is right there
41 * in the resources table) as well as through a separate MAX17047 device.
42 *
43 * These helpers are used to work around this by checking if an i2c-client
44 * for the max17047 has already been registered.
45 */
46static int cht_int33fe_check_for_max17047(struct device *dev, void *data)
47{
48 struct i2c_client **max17047 = data;
49 struct acpi_device *adev;
50 const char *hid;
51
52 adev = ACPI_COMPANION(dev);
53 if (!adev)
54 return 0;
55
56 hid = acpi_device_hid(adev);
57
58 /* The MAX17047 ACPI node doesn't have an UID, so we don't check that */
59 if (strcmp(hid, "MAX17047"))
60 return 0;
61
62 *max17047 = to_i2c_client(dev);
63 return 1;
64}
65
66static struct i2c_client *cht_int33fe_find_max17047(void)
67{
68 struct i2c_client *max17047 = NULL;
69
70 i2c_for_each_dev(&max17047, cht_int33fe_check_for_max17047);
71 return max17047;
72}
73
37static const char * const max17047_suppliers[] = { "bq24190-charger" }; 74static const char * const max17047_suppliers[] = { "bq24190-charger" };
38 75
39static const struct property_entry max17047_props[] = { 76static const struct property_entry max17047_props[] = {
@@ -41,14 +78,25 @@ static const struct property_entry max17047_props[] = {
41 { } 78 { }
42}; 79};
43 80
81static const struct property_entry fusb302_props[] = {
82 PROPERTY_ENTRY_STRING("fcs,extcon-name", "cht_wcove_pwrsrc"),
83 PROPERTY_ENTRY_U32("fcs,max-sink-microvolt", 12000000),
84 PROPERTY_ENTRY_U32("fcs,max-sink-microamp", 3000000),
85 PROPERTY_ENTRY_U32("fcs,max-sink-microwatt", 36000000),
86 { }
87};
88
44static int cht_int33fe_probe(struct i2c_client *client) 89static int cht_int33fe_probe(struct i2c_client *client)
45{ 90{
46 struct device *dev = &client->dev; 91 struct device *dev = &client->dev;
47 struct i2c_board_info board_info; 92 struct i2c_board_info board_info;
48 struct cht_int33fe_data *data; 93 struct cht_int33fe_data *data;
94 struct i2c_client *max17047;
95 struct regulator *regulator;
49 unsigned long long ptyp; 96 unsigned long long ptyp;
50 acpi_status status; 97 acpi_status status;
51 int fusb302_irq; 98 int fusb302_irq;
99 int ret;
52 100
53 status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PTYP", NULL, &ptyp); 101 status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PTYP", NULL, &ptyp);
54 if (ACPI_FAILURE(status)) { 102 if (ACPI_FAILURE(status)) {
@@ -63,6 +111,34 @@ static int cht_int33fe_probe(struct i2c_client *client)
63 if (ptyp != EXPECTED_PTYPE) 111 if (ptyp != EXPECTED_PTYPE)
64 return -ENODEV; 112 return -ENODEV;
65 113
114 /* Check presence of INT34D3 (hardware-rev 3) expected for ptype == 4 */
115 if (!acpi_dev_present("INT34D3", "1", 3)) {
116 dev_err(dev, "Error PTYPE == %d, but no INT34D3 device\n",
117 EXPECTED_PTYPE);
118 return -ENODEV;
119 }
120
121 /*
122 * We expect the WC PMIC to be paired with a TI bq24292i charger-IC.
123 * We check for the bq24292i vbus regulator here, this has 2 purposes:
124 * 1) The bq24292i allows charging with up to 12V, setting the fusb302's
125 * max-snk voltage to 12V with another charger-IC is not good.
126 * 2) For the fusb302 driver to get the bq24292i vbus regulator, the
127 * regulator-map, which is part of the bq24292i regulator_init_data,
128 * must be registered before the fusb302 is instantiated, otherwise
129 * it will end up with a dummy-regulator.
130 * Note "cht_wc_usb_typec_vbus" comes from the regulator_init_data
131 * which is defined in i2c-cht-wc.c from where the bq24292i i2c-client
132 * gets instantiated. We use regulator_get_optional here so that we
133 * don't end up getting a dummy-regulator ourselves.
134 */
135 regulator = regulator_get_optional(dev, "cht_wc_usb_typec_vbus");
136 if (IS_ERR(regulator)) {
137 ret = PTR_ERR(regulator);
138 return (ret == -ENODEV) ? -EPROBE_DEFER : ret;
139 }
140 regulator_put(regulator);
141
66 /* The FUSB302 uses the irq at index 1 and is the only irq user */ 142 /* The FUSB302 uses the irq at index 1 and is the only irq user */
67 fusb302_irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 1); 143 fusb302_irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 1);
68 if (fusb302_irq < 0) { 144 if (fusb302_irq < 0) {
@@ -75,16 +151,31 @@ static int cht_int33fe_probe(struct i2c_client *client)
75 if (!data) 151 if (!data)
76 return -ENOMEM; 152 return -ENOMEM;
77 153
78 memset(&board_info, 0, sizeof(board_info)); 154 /* Work around BIOS bug, see comment on cht_int33fe_find_max17047 */
79 strlcpy(board_info.type, "max17047", I2C_NAME_SIZE); 155 max17047 = cht_int33fe_find_max17047();
80 board_info.properties = max17047_props; 156 if (max17047) {
81 157 /* Pre-existing i2c-client for the max17047, add device-props */
82 data->max17047 = i2c_acpi_new_device(dev, 1, &board_info); 158 ret = device_add_properties(&max17047->dev, max17047_props);
83 if (!data->max17047) 159 if (ret)
84 return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */ 160 return ret;
161 /* And re-probe to get the new device-props applied. */
162 ret = device_reprobe(&max17047->dev);
163 if (ret)
164 dev_warn(dev, "Reprobing max17047 error: %d\n", ret);
165 } else {
166 memset(&board_info, 0, sizeof(board_info));
167 strlcpy(board_info.type, "max17047", I2C_NAME_SIZE);
168 board_info.dev_name = "max17047";
169 board_info.properties = max17047_props;
170 data->max17047 = i2c_acpi_new_device(dev, 1, &board_info);
171 if (!data->max17047)
172 return -EPROBE_DEFER; /* Wait for i2c-adapter to load */
173 }
85 174
86 memset(&board_info, 0, sizeof(board_info)); 175 memset(&board_info, 0, sizeof(board_info));
87 strlcpy(board_info.type, "fusb302", I2C_NAME_SIZE); 176 strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE);
177 board_info.dev_name = "fusb302";
178 board_info.properties = fusb302_props;
88 board_info.irq = fusb302_irq; 179 board_info.irq = fusb302_irq;
89 180
90 data->fusb302 = i2c_acpi_new_device(dev, 2, &board_info); 181 data->fusb302 = i2c_acpi_new_device(dev, 2, &board_info);
@@ -92,6 +183,7 @@ static int cht_int33fe_probe(struct i2c_client *client)
92 goto out_unregister_max17047; 183 goto out_unregister_max17047;
93 184
94 memset(&board_info, 0, sizeof(board_info)); 185 memset(&board_info, 0, sizeof(board_info));
186 board_info.dev_name = "pi3usb30532";
95 strlcpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE); 187 strlcpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE);
96 188
97 data->pi3usb30532 = i2c_acpi_new_device(dev, 3, &board_info); 189 data->pi3usb30532 = i2c_acpi_new_device(dev, 3, &board_info);
@@ -106,7 +198,8 @@ out_unregister_fusb302:
106 i2c_unregister_device(data->fusb302); 198 i2c_unregister_device(data->fusb302);
107 199
108out_unregister_max17047: 200out_unregister_max17047:
109 i2c_unregister_device(data->max17047); 201 if (data->max17047)
202 i2c_unregister_device(data->max17047);
110 203
111 return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */ 204 return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */
112} 205}
@@ -117,7 +210,8 @@ static int cht_int33fe_remove(struct i2c_client *i2c)
117 210
118 i2c_unregister_device(data->pi3usb30532); 211 i2c_unregister_device(data->pi3usb30532);
119 i2c_unregister_device(data->fusb302); 212 i2c_unregister_device(data->fusb302);
120 i2c_unregister_device(data->max17047); 213 if (data->max17047)
214 i2c_unregister_device(data->max17047);
121 215
122 return 0; 216 return 0;
123} 217}
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c
index 58dcee562d64..a0c95853fd3f 100644
--- a/drivers/platform/x86/intel_ips.c
+++ b/drivers/platform/x86/intel_ips.c
@@ -10,10 +10,6 @@
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details. 11 * more details.
12 * 12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
16 *
17 * The full GNU General Public License is included in this distribution in 13 * The full GNU General Public License is included in this distribution in
18 * the file called "COPYING". 14 * the file called "COPYING".
19 * 15 *
@@ -259,8 +255,6 @@ static const int IPS_SAMPLE_WINDOW = 5000; /* 5s moving window of samples */
259 255
260/* Per-SKU limits */ 256/* Per-SKU limits */
261struct ips_mcp_limits { 257struct ips_mcp_limits {
262 int cpu_family;
263 int cpu_model; /* includes extended model... */
264 int mcp_power_limit; /* mW units */ 258 int mcp_power_limit; /* mW units */
265 int core_power_limit; 259 int core_power_limit;
266 int mch_power_limit; 260 int mch_power_limit;
@@ -295,11 +289,14 @@ static struct ips_mcp_limits ips_ulv_limits = {
295}; 289};
296 290
297struct ips_driver { 291struct ips_driver {
298 struct pci_dev *dev; 292 struct device *dev;
299 void *regmap; 293 void __iomem *regmap;
294 int irq;
295
300 struct task_struct *monitor; 296 struct task_struct *monitor;
301 struct task_struct *adjust; 297 struct task_struct *adjust;
302 struct dentry *debug_root; 298 struct dentry *debug_root;
299 struct timer_list timer;
303 300
304 /* Average CPU core temps (all averages in .01 degrees C for precision) */ 301 /* Average CPU core temps (all averages in .01 degrees C for precision) */
305 u16 ctv1_avg_temp; 302 u16 ctv1_avg_temp;
@@ -594,7 +591,7 @@ static void ips_disable_gpu_turbo(struct ips_driver *ips)
594 return; 591 return;
595 592
596 if (!ips->gpu_turbo_disable()) 593 if (!ips->gpu_turbo_disable())
597 dev_err(&ips->dev->dev, "failed to disable graphics turbo\n"); 594 dev_err(ips->dev, "failed to disable graphics turbo\n");
598 else 595 else
599 ips->__gpu_turbo_on = false; 596 ips->__gpu_turbo_on = false;
600} 597}
@@ -649,8 +646,7 @@ static bool cpu_exceeded(struct ips_driver *ips, int cpu)
649 spin_unlock_irqrestore(&ips->turbo_status_lock, flags); 646 spin_unlock_irqrestore(&ips->turbo_status_lock, flags);
650 647
651 if (ret) 648 if (ret)
652 dev_info(&ips->dev->dev, 649 dev_info(ips->dev, "CPU power or thermal limit exceeded\n");
653 "CPU power or thermal limit exceeded\n");
654 650
655 return ret; 651 return ret;
656} 652}
@@ -769,7 +765,7 @@ static int ips_adjust(void *data)
769 struct ips_driver *ips = data; 765 struct ips_driver *ips = data;
770 unsigned long flags; 766 unsigned long flags;
771 767
772 dev_dbg(&ips->dev->dev, "starting ips-adjust thread\n"); 768 dev_dbg(ips->dev, "starting ips-adjust thread\n");
773 769
774 /* 770 /*
775 * Adjust CPU and GPU clamps every 5s if needed. Doing it more 771 * Adjust CPU and GPU clamps every 5s if needed. Doing it more
@@ -816,7 +812,7 @@ sleep:
816 schedule_timeout_interruptible(msecs_to_jiffies(IPS_ADJUST_PERIOD)); 812 schedule_timeout_interruptible(msecs_to_jiffies(IPS_ADJUST_PERIOD));
817 } while (!kthread_should_stop()); 813 } while (!kthread_should_stop());
818 814
819 dev_dbg(&ips->dev->dev, "ips-adjust thread stopped\n"); 815 dev_dbg(ips->dev, "ips-adjust thread stopped\n");
820 816
821 return 0; 817 return 0;
822} 818}
@@ -942,9 +938,10 @@ static u32 calc_avg_power(struct ips_driver *ips, u32 *array)
942 return avg; 938 return avg;
943} 939}
944 940
945static void monitor_timeout(unsigned long arg) 941static void monitor_timeout(struct timer_list *t)
946{ 942{
947 wake_up_process((struct task_struct *)arg); 943 struct ips_driver *ips = from_timer(ips, t, timer);
944 wake_up_process(ips->monitor);
948} 945}
949 946
950/** 947/**
@@ -961,7 +958,6 @@ static void monitor_timeout(unsigned long arg)
961static int ips_monitor(void *data) 958static int ips_monitor(void *data)
962{ 959{
963 struct ips_driver *ips = data; 960 struct ips_driver *ips = data;
964 struct timer_list timer;
965 unsigned long seqno_timestamp, expire, last_msecs, last_sample_period; 961 unsigned long seqno_timestamp, expire, last_msecs, last_sample_period;
966 int i; 962 int i;
967 u32 *cpu_samples, *mchp_samples, old_cpu_power; 963 u32 *cpu_samples, *mchp_samples, old_cpu_power;
@@ -976,7 +972,7 @@ static int ips_monitor(void *data)
976 mchp_samples = kzalloc(sizeof(u32) * IPS_SAMPLE_COUNT, GFP_KERNEL); 972 mchp_samples = kzalloc(sizeof(u32) * IPS_SAMPLE_COUNT, GFP_KERNEL);
977 if (!mcp_samples || !ctv1_samples || !ctv2_samples || !mch_samples || 973 if (!mcp_samples || !ctv1_samples || !ctv2_samples || !mch_samples ||
978 !cpu_samples || !mchp_samples) { 974 !cpu_samples || !mchp_samples) {
979 dev_err(&ips->dev->dev, 975 dev_err(ips->dev,
980 "failed to allocate sample array, ips disabled\n"); 976 "failed to allocate sample array, ips disabled\n");
981 kfree(mcp_samples); 977 kfree(mcp_samples);
982 kfree(ctv1_samples); 978 kfree(ctv1_samples);
@@ -1049,8 +1045,7 @@ static int ips_monitor(void *data)
1049 schedule_timeout_interruptible(msecs_to_jiffies(IPS_SAMPLE_PERIOD)); 1045 schedule_timeout_interruptible(msecs_to_jiffies(IPS_SAMPLE_PERIOD));
1050 last_sample_period = IPS_SAMPLE_PERIOD; 1046 last_sample_period = IPS_SAMPLE_PERIOD;
1051 1047
1052 setup_deferrable_timer_on_stack(&timer, monitor_timeout, 1048 timer_setup(&ips->timer, monitor_timeout, TIMER_DEFERRABLE);
1053 (unsigned long)current);
1054 do { 1049 do {
1055 u32 cpu_val, mch_val; 1050 u32 cpu_val, mch_val;
1056 u16 val; 1051 u16 val;
@@ -1097,7 +1092,8 @@ static int ips_monitor(void *data)
1097 ITV_ME_SEQNO_SHIFT; 1092 ITV_ME_SEQNO_SHIFT;
1098 if (cur_seqno == last_seqno && 1093 if (cur_seqno == last_seqno &&
1099 time_after(jiffies, seqno_timestamp + HZ)) { 1094 time_after(jiffies, seqno_timestamp + HZ)) {
1100 dev_warn(&ips->dev->dev, "ME failed to update for more than 1s, likely hung\n"); 1095 dev_warn(ips->dev,
1096 "ME failed to update for more than 1s, likely hung\n");
1101 } else { 1097 } else {
1102 seqno_timestamp = get_jiffies_64(); 1098 seqno_timestamp = get_jiffies_64();
1103 last_seqno = cur_seqno; 1099 last_seqno = cur_seqno;
@@ -1107,7 +1103,7 @@ static int ips_monitor(void *data)
1107 expire = jiffies + msecs_to_jiffies(IPS_SAMPLE_PERIOD); 1103 expire = jiffies + msecs_to_jiffies(IPS_SAMPLE_PERIOD);
1108 1104
1109 __set_current_state(TASK_INTERRUPTIBLE); 1105 __set_current_state(TASK_INTERRUPTIBLE);
1110 mod_timer(&timer, expire); 1106 mod_timer(&ips->timer, expire);
1111 schedule(); 1107 schedule();
1112 1108
1113 /* Calculate actual sample period for power averaging */ 1109 /* Calculate actual sample period for power averaging */
@@ -1116,10 +1112,9 @@ static int ips_monitor(void *data)
1116 last_sample_period = 1; 1112 last_sample_period = 1;
1117 } while (!kthread_should_stop()); 1113 } while (!kthread_should_stop());
1118 1114
1119 del_timer_sync(&timer); 1115 del_timer_sync(&ips->timer);
1120 destroy_timer_on_stack(&timer);
1121 1116
1122 dev_dbg(&ips->dev->dev, "ips-monitor thread stopped\n"); 1117 dev_dbg(ips->dev, "ips-monitor thread stopped\n");
1123 1118
1124 return 0; 1119 return 0;
1125} 1120}
@@ -1128,17 +1123,17 @@ static int ips_monitor(void *data)
1128#define THM_DUMPW(reg) \ 1123#define THM_DUMPW(reg) \
1129 { \ 1124 { \
1130 u16 val = thm_readw(reg); \ 1125 u16 val = thm_readw(reg); \
1131 dev_dbg(&ips->dev->dev, #reg ": 0x%04x\n", val); \ 1126 dev_dbg(ips->dev, #reg ": 0x%04x\n", val); \
1132 } 1127 }
1133#define THM_DUMPL(reg) \ 1128#define THM_DUMPL(reg) \
1134 { \ 1129 { \
1135 u32 val = thm_readl(reg); \ 1130 u32 val = thm_readl(reg); \
1136 dev_dbg(&ips->dev->dev, #reg ": 0x%08x\n", val); \ 1131 dev_dbg(ips->dev, #reg ": 0x%08x\n", val); \
1137 } 1132 }
1138#define THM_DUMPQ(reg) \ 1133#define THM_DUMPQ(reg) \
1139 { \ 1134 { \
1140 u64 val = thm_readq(reg); \ 1135 u64 val = thm_readq(reg); \
1141 dev_dbg(&ips->dev->dev, #reg ": 0x%016x\n", val); \ 1136 dev_dbg(ips->dev, #reg ": 0x%016x\n", val); \
1142 } 1137 }
1143 1138
1144static void dump_thermal_info(struct ips_driver *ips) 1139static void dump_thermal_info(struct ips_driver *ips)
@@ -1146,7 +1141,7 @@ static void dump_thermal_info(struct ips_driver *ips)
1146 u16 ptl; 1141 u16 ptl;
1147 1142
1148 ptl = thm_readw(THM_PTL); 1143 ptl = thm_readw(THM_PTL);
1149 dev_dbg(&ips->dev->dev, "Processor temp limit: %d\n", ptl); 1144 dev_dbg(ips->dev, "Processor temp limit: %d\n", ptl);
1150 1145
1151 THM_DUMPW(THM_CTA); 1146 THM_DUMPW(THM_CTA);
1152 THM_DUMPW(THM_TRC); 1147 THM_DUMPW(THM_TRC);
@@ -1175,8 +1170,8 @@ static irqreturn_t ips_irq_handler(int irq, void *arg)
1175 if (!tses && !tes) 1170 if (!tses && !tes)
1176 return IRQ_NONE; 1171 return IRQ_NONE;
1177 1172
1178 dev_info(&ips->dev->dev, "TSES: 0x%02x\n", tses); 1173 dev_info(ips->dev, "TSES: 0x%02x\n", tses);
1179 dev_info(&ips->dev->dev, "TES: 0x%02x\n", tes); 1174 dev_info(ips->dev, "TES: 0x%02x\n", tes);
1180 1175
1181 /* STS update from EC? */ 1176 /* STS update from EC? */
1182 if (tes & 1) { 1177 if (tes & 1) {
@@ -1214,8 +1209,8 @@ static irqreturn_t ips_irq_handler(int irq, void *arg)
1214 1209
1215 /* Thermal trip */ 1210 /* Thermal trip */
1216 if (tses) { 1211 if (tses) {
1217 dev_warn(&ips->dev->dev, 1212 dev_warn(ips->dev, "thermal trip occurred, tses: 0x%04x\n",
1218 "thermal trip occurred, tses: 0x%04x\n", tses); 1213 tses);
1219 thm_writeb(THM_TSES, tses); 1214 thm_writeb(THM_TSES, tses);
1220 } 1215 }
1221 1216
@@ -1330,8 +1325,7 @@ static void ips_debugfs_init(struct ips_driver *ips)
1330 1325
1331 ips->debug_root = debugfs_create_dir("ips", NULL); 1326 ips->debug_root = debugfs_create_dir("ips", NULL);
1332 if (!ips->debug_root) { 1327 if (!ips->debug_root) {
1333 dev_err(&ips->dev->dev, 1328 dev_err(ips->dev, "failed to create debugfs entries: %ld\n",
1334 "failed to create debugfs entries: %ld\n",
1335 PTR_ERR(ips->debug_root)); 1329 PTR_ERR(ips->debug_root));
1336 return; 1330 return;
1337 } 1331 }
@@ -1345,8 +1339,7 @@ static void ips_debugfs_init(struct ips_driver *ips)
1345 ips->debug_root, node, 1339 ips->debug_root, node,
1346 &ips_debugfs_ops); 1340 &ips_debugfs_ops);
1347 if (!ent) { 1341 if (!ent) {
1348 dev_err(&ips->dev->dev, 1342 dev_err(ips->dev, "failed to create debug file: %ld\n",
1349 "failed to create debug file: %ld\n",
1350 PTR_ERR(ent)); 1343 PTR_ERR(ent));
1351 goto err_cleanup; 1344 goto err_cleanup;
1352 } 1345 }
@@ -1373,8 +1366,8 @@ static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips)
1373 u16 tdp; 1366 u16 tdp;
1374 1367
1375 if (!(boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 37)) { 1368 if (!(boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 37)) {
1376 dev_info(&ips->dev->dev, "Non-IPS CPU detected.\n"); 1369 dev_info(ips->dev, "Non-IPS CPU detected.\n");
1377 goto out; 1370 return NULL;
1378 } 1371 }
1379 1372
1380 rdmsrl(IA32_MISC_ENABLE, misc_en); 1373 rdmsrl(IA32_MISC_ENABLE, misc_en);
@@ -1395,8 +1388,8 @@ static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips)
1395 else if (strstr(boot_cpu_data.x86_model_id, "CPU U")) 1388 else if (strstr(boot_cpu_data.x86_model_id, "CPU U"))
1396 limits = &ips_ulv_limits; 1389 limits = &ips_ulv_limits;
1397 else { 1390 else {
1398 dev_info(&ips->dev->dev, "No CPUID match found.\n"); 1391 dev_info(ips->dev, "No CPUID match found.\n");
1399 goto out; 1392 return NULL;
1400 } 1393 }
1401 1394
1402 rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_power); 1395 rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_power);
@@ -1404,12 +1397,12 @@ static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips)
1404 1397
1405 /* Sanity check TDP against CPU */ 1398 /* Sanity check TDP against CPU */
1406 if (limits->core_power_limit != (tdp / 8) * 1000) { 1399 if (limits->core_power_limit != (tdp / 8) * 1000) {
1407 dev_info(&ips->dev->dev, "CPU TDP doesn't match expected value (found %d, expected %d)\n", 1400 dev_info(ips->dev,
1401 "CPU TDP doesn't match expected value (found %d, expected %d)\n",
1408 tdp / 8, limits->core_power_limit / 1000); 1402 tdp / 8, limits->core_power_limit / 1000);
1409 limits->core_power_limit = (tdp / 8) * 1000; 1403 limits->core_power_limit = (tdp / 8) * 1000;
1410 } 1404 }
1411 1405
1412out:
1413 return limits; 1406 return limits;
1414} 1407}
1415 1408
@@ -1459,7 +1452,7 @@ ips_gpu_turbo_enabled(struct ips_driver *ips)
1459{ 1452{
1460 if (!ips->gpu_busy && late_i915_load) { 1453 if (!ips->gpu_busy && late_i915_load) {
1461 if (ips_get_i915_syms(ips)) { 1454 if (ips_get_i915_syms(ips)) {
1462 dev_info(&ips->dev->dev, 1455 dev_info(ips->dev,
1463 "i915 driver attached, reenabling gpu turbo\n"); 1456 "i915 driver attached, reenabling gpu turbo\n");
1464 ips->gpu_turbo_enabled = !(thm_readl(THM_HTS) & HTS_GTD_DIS); 1457 ips->gpu_turbo_enabled = !(thm_readl(THM_HTS) & HTS_GTD_DIS);
1465 } 1458 }
@@ -1480,8 +1473,7 @@ ips_link_to_i915_driver(void)
1480EXPORT_SYMBOL_GPL(ips_link_to_i915_driver); 1473EXPORT_SYMBOL_GPL(ips_link_to_i915_driver);
1481 1474
1482static const struct pci_device_id ips_id_table[] = { 1475static const struct pci_device_id ips_id_table[] = {
1483 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 1476 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_THERMAL_SENSOR), },
1484 PCI_DEVICE_ID_INTEL_THERMAL_SENSOR), },
1485 { 0, } 1477 { 0, }
1486}; 1478};
1487 1479
@@ -1517,62 +1509,45 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id)
1517 if (dmi_check_system(ips_blacklist)) 1509 if (dmi_check_system(ips_blacklist))
1518 return -ENODEV; 1510 return -ENODEV;
1519 1511
1520 ips = kzalloc(sizeof(struct ips_driver), GFP_KERNEL); 1512 ips = devm_kzalloc(&dev->dev, sizeof(*ips), GFP_KERNEL);
1521 if (!ips) 1513 if (!ips)
1522 return -ENOMEM; 1514 return -ENOMEM;
1523 1515
1524 pci_set_drvdata(dev, ips); 1516 spin_lock_init(&ips->turbo_status_lock);
1525 ips->dev = dev; 1517 ips->dev = &dev->dev;
1526 1518
1527 ips->limits = ips_detect_cpu(ips); 1519 ips->limits = ips_detect_cpu(ips);
1528 if (!ips->limits) { 1520 if (!ips->limits) {
1529 dev_info(&dev->dev, "IPS not supported on this CPU\n"); 1521 dev_info(&dev->dev, "IPS not supported on this CPU\n");
1530 ret = -ENXIO; 1522 return -ENXIO;
1531 goto error_free;
1532 } 1523 }
1533 1524
1534 spin_lock_init(&ips->turbo_status_lock); 1525 ret = pcim_enable_device(dev);
1535
1536 ret = pci_enable_device(dev);
1537 if (ret) { 1526 if (ret) {
1538 dev_err(&dev->dev, "can't enable PCI device, aborting\n"); 1527 dev_err(&dev->dev, "can't enable PCI device, aborting\n");
1539 goto error_free; 1528 return ret;
1540 } 1529 }
1541 1530
1542 if (!pci_resource_start(dev, 0)) { 1531 ret = pcim_iomap_regions(dev, 1 << 0, pci_name(dev));
1543 dev_err(&dev->dev, "TBAR not assigned, aborting\n");
1544 ret = -ENXIO;
1545 goto error_free;
1546 }
1547
1548 ret = pci_request_regions(dev, "ips thermal sensor");
1549 if (ret) { 1532 if (ret) {
1550 dev_err(&dev->dev, "thermal resource busy, aborting\n");
1551 goto error_free;
1552 }
1553
1554
1555 ips->regmap = ioremap(pci_resource_start(dev, 0),
1556 pci_resource_len(dev, 0));
1557 if (!ips->regmap) {
1558 dev_err(&dev->dev, "failed to map thermal regs, aborting\n"); 1533 dev_err(&dev->dev, "failed to map thermal regs, aborting\n");
1559 ret = -EBUSY; 1534 return ret;
1560 goto error_release;
1561 } 1535 }
1536 ips->regmap = pcim_iomap_table(dev)[0];
1537
1538 pci_set_drvdata(dev, ips);
1562 1539
1563 tse = thm_readb(THM_TSE); 1540 tse = thm_readb(THM_TSE);
1564 if (tse != TSE_EN) { 1541 if (tse != TSE_EN) {
1565 dev_err(&dev->dev, "thermal device not enabled (0x%02x), aborting\n", tse); 1542 dev_err(&dev->dev, "thermal device not enabled (0x%02x), aborting\n", tse);
1566 ret = -ENXIO; 1543 return -ENXIO;
1567 goto error_unmap;
1568 } 1544 }
1569 1545
1570 trc = thm_readw(THM_TRC); 1546 trc = thm_readw(THM_TRC);
1571 trc_required_mask = TRC_CORE1_EN | TRC_CORE_PWR | TRC_MCH_EN; 1547 trc_required_mask = TRC_CORE1_EN | TRC_CORE_PWR | TRC_MCH_EN;
1572 if ((trc & trc_required_mask) != trc_required_mask) { 1548 if ((trc & trc_required_mask) != trc_required_mask) {
1573 dev_err(&dev->dev, "thermal reporting for required devices not enabled, aborting\n"); 1549 dev_err(&dev->dev, "thermal reporting for required devices not enabled, aborting\n");
1574 ret = -ENXIO; 1550 return -ENXIO;
1575 goto error_unmap;
1576 } 1551 }
1577 1552
1578 if (trc & TRC_CORE2_EN) 1553 if (trc & TRC_CORE2_EN)
@@ -1602,20 +1577,23 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id)
1602 rdmsrl(PLATFORM_INFO, platform_info); 1577 rdmsrl(PLATFORM_INFO, platform_info);
1603 if (!(platform_info & PLATFORM_TDP)) { 1578 if (!(platform_info & PLATFORM_TDP)) {
1604 dev_err(&dev->dev, "platform indicates TDP override unavailable, aborting\n"); 1579 dev_err(&dev->dev, "platform indicates TDP override unavailable, aborting\n");
1605 ret = -ENODEV; 1580 return -ENODEV;
1606 goto error_unmap;
1607 } 1581 }
1608 1582
1609 /* 1583 /*
1610 * IRQ handler for ME interaction 1584 * IRQ handler for ME interaction
1611 * Note: don't use MSI here as the PCH has bugs. 1585 * Note: don't use MSI here as the PCH has bugs.
1612 */ 1586 */
1613 pci_disable_msi(dev); 1587 ret = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY);
1614 ret = request_irq(dev->irq, ips_irq_handler, IRQF_SHARED, "ips", 1588 if (ret < 0)
1615 ips); 1589 return ret;
1590
1591 ips->irq = pci_irq_vector(dev, 0);
1592
1593 ret = request_irq(ips->irq, ips_irq_handler, IRQF_SHARED, "ips", ips);
1616 if (ret) { 1594 if (ret) {
1617 dev_err(&dev->dev, "request irq failed, aborting\n"); 1595 dev_err(&dev->dev, "request irq failed, aborting\n");
1618 goto error_unmap; 1596 return ret;
1619 } 1597 }
1620 1598
1621 /* Enable aux, hot & critical interrupts */ 1599 /* Enable aux, hot & critical interrupts */
@@ -1672,13 +1650,8 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id)
1672error_thread_cleanup: 1650error_thread_cleanup:
1673 kthread_stop(ips->adjust); 1651 kthread_stop(ips->adjust);
1674error_free_irq: 1652error_free_irq:
1675 free_irq(ips->dev->irq, ips); 1653 free_irq(ips->irq, ips);
1676error_unmap: 1654 pci_free_irq_vectors(dev);
1677 iounmap(ips->regmap);
1678error_release:
1679 pci_release_regions(dev);
1680error_free:
1681 kfree(ips);
1682 return ret; 1655 return ret;
1683} 1656}
1684 1657
@@ -1709,27 +1682,20 @@ static void ips_remove(struct pci_dev *dev)
1709 wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override); 1682 wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
1710 wrmsrl(TURBO_POWER_CURRENT_LIMIT, ips->orig_turbo_limit); 1683 wrmsrl(TURBO_POWER_CURRENT_LIMIT, ips->orig_turbo_limit);
1711 1684
1712 free_irq(ips->dev->irq, ips); 1685 free_irq(ips->irq, ips);
1686 pci_free_irq_vectors(dev);
1713 if (ips->adjust) 1687 if (ips->adjust)
1714 kthread_stop(ips->adjust); 1688 kthread_stop(ips->adjust);
1715 if (ips->monitor) 1689 if (ips->monitor)
1716 kthread_stop(ips->monitor); 1690 kthread_stop(ips->monitor);
1717 iounmap(ips->regmap);
1718 pci_release_regions(dev);
1719 kfree(ips);
1720 dev_dbg(&dev->dev, "IPS driver removed\n"); 1691 dev_dbg(&dev->dev, "IPS driver removed\n");
1721} 1692}
1722 1693
1723static void ips_shutdown(struct pci_dev *dev)
1724{
1725}
1726
1727static struct pci_driver ips_pci_driver = { 1694static struct pci_driver ips_pci_driver = {
1728 .name = "intel ips", 1695 .name = "intel ips",
1729 .id_table = ips_id_table, 1696 .id_table = ips_id_table,
1730 .probe = ips_probe, 1697 .probe = ips_probe,
1731 .remove = ips_remove, 1698 .remove = ips_remove,
1732 .shutdown = ips_shutdown,
1733}; 1699};
1734 1700
1735module_pci_driver(ips_pci_driver); 1701module_pci_driver(ips_pci_driver);
diff --git a/drivers/platform/x86/intel_ips.h b/drivers/platform/x86/intel_ips.h
index 73299beff5b3..60f4e3ddbe9f 100644
--- a/drivers/platform/x86/intel_ips.h
+++ b/drivers/platform/x86/intel_ips.h
@@ -10,10 +10,6 @@
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details. 11 * more details.
12 * 12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
16 *
17 * The full GNU General Public License is included in this distribution in 13 * The full GNU General Public License is included in this distribution in
18 * the file called "COPYING". 14 * the file called "COPYING".
19 */ 15 */
diff --git a/drivers/platform/x86/intel_punit_ipc.c b/drivers/platform/x86/intel_punit_ipc.c
index a47a41fc10ad..b5b890127479 100644
--- a/drivers/platform/x86/intel_punit_ipc.c
+++ b/drivers/platform/x86/intel_punit_ipc.c
@@ -252,28 +252,28 @@ static int intel_punit_get_bars(struct platform_device *pdev)
252 * - GTDRIVER_IPC BASE_IFACE 252 * - GTDRIVER_IPC BASE_IFACE
253 */ 253 */
254 res = platform_get_resource(pdev, IORESOURCE_MEM, 2); 254 res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
255 if (res) { 255 if (res && resource_size(res) > 1) {
256 addr = devm_ioremap_resource(&pdev->dev, res); 256 addr = devm_ioremap_resource(&pdev->dev, res);
257 if (!IS_ERR(addr)) 257 if (!IS_ERR(addr))
258 punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr; 258 punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr;
259 } 259 }
260 260
261 res = platform_get_resource(pdev, IORESOURCE_MEM, 3); 261 res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
262 if (res) { 262 if (res && resource_size(res) > 1) {
263 addr = devm_ioremap_resource(&pdev->dev, res); 263 addr = devm_ioremap_resource(&pdev->dev, res);
264 if (!IS_ERR(addr)) 264 if (!IS_ERR(addr))
265 punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr; 265 punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr;
266 } 266 }
267 267
268 res = platform_get_resource(pdev, IORESOURCE_MEM, 4); 268 res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
269 if (res) { 269 if (res && resource_size(res) > 1) {
270 addr = devm_ioremap_resource(&pdev->dev, res); 270 addr = devm_ioremap_resource(&pdev->dev, res);
271 if (!IS_ERR(addr)) 271 if (!IS_ERR(addr))
272 punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr; 272 punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr;
273 } 273 }
274 274
275 res = platform_get_resource(pdev, IORESOURCE_MEM, 5); 275 res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
276 if (res) { 276 if (res && resource_size(res) > 1) {
277 addr = devm_ioremap_resource(&pdev->dev, res); 277 addr = devm_ioremap_resource(&pdev->dev, res);
278 if (!IS_ERR(addr)) 278 if (!IS_ERR(addr))
279 punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr; 279 punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr;
diff --git a/drivers/platform/x86/intel_telemetry_core.c b/drivers/platform/x86/intel_telemetry_core.c
index 0d4c3808a6d8..f378621b5fe9 100644
--- a/drivers/platform/x86/intel_telemetry_core.c
+++ b/drivers/platform/x86/intel_telemetry_core.c
@@ -15,9 +15,8 @@
15 * Telemetry Framework provides platform related PM and performance statistics. 15 * Telemetry Framework provides platform related PM and performance statistics.
16 * This file provides the core telemetry API implementation. 16 * This file provides the core telemetry API implementation.
17 */ 17 */
18#include <linux/module.h>
19#include <linux/init.h>
20#include <linux/device.h> 18#include <linux/device.h>
19#include <linux/module.h>
21 20
22#include <asm/intel_telemetry.h> 21#include <asm/intel_telemetry.h>
23 22
diff --git a/drivers/platform/x86/intel_telemetry_debugfs.c b/drivers/platform/x86/intel_telemetry_debugfs.c
index d4fc42b4cbeb..4249e8267bbc 100644
--- a/drivers/platform/x86/intel_telemetry_debugfs.c
+++ b/drivers/platform/x86/intel_telemetry_debugfs.c
@@ -21,14 +21,12 @@
21 * /sys/kernel/debug/telemetry/ioss_race_verbosity: Write and Change Tracing 21 * /sys/kernel/debug/telemetry/ioss_race_verbosity: Write and Change Tracing
22 * Verbosity via firmware 22 * Verbosity via firmware
23 */ 23 */
24#include <linux/module.h>
25#include <linux/init.h>
26#include <linux/device.h>
27#include <linux/debugfs.h> 24#include <linux/debugfs.h>
28#include <linux/seq_file.h> 25#include <linux/device.h>
29#include <linux/io.h> 26#include <linux/io.h>
30#include <linux/uaccess.h> 27#include <linux/module.h>
31#include <linux/pci.h> 28#include <linux/pci.h>
29#include <linux/seq_file.h>
32#include <linux/suspend.h> 30#include <linux/suspend.h>
33 31
34#include <asm/cpu_device_id.h> 32#include <asm/cpu_device_id.h>
@@ -76,8 +74,6 @@
76#define TELEM_IOSS_DX_D0IX_EVTS 25 74#define TELEM_IOSS_DX_D0IX_EVTS 25
77#define TELEM_IOSS_PG_EVTS 30 75#define TELEM_IOSS_PG_EVTS 30
78 76
79#define TELEM_EVT_LEN(x) (sizeof(x)/sizeof((x)[0]))
80
81#define TELEM_DEBUGFS_CPU(model, data) \ 77#define TELEM_DEBUGFS_CPU(model, data) \
82 { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&data} 78 { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&data}
83 79
@@ -304,13 +300,13 @@ static struct telemetry_debugfs_conf telem_apl_debugfs_conf = {
304 .ioss_d0ix_data = telem_apl_ioss_d0ix_data, 300 .ioss_d0ix_data = telem_apl_ioss_d0ix_data,
305 .ioss_pg_data = telem_apl_ioss_pg_data, 301 .ioss_pg_data = telem_apl_ioss_pg_data,
306 302
307 .pss_idle_evts = TELEM_EVT_LEN(telem_apl_pss_idle_data), 303 .pss_idle_evts = ARRAY_SIZE(telem_apl_pss_idle_data),
308 .pcs_idle_blkd_evts = TELEM_EVT_LEN(telem_apl_pcs_idle_blkd_data), 304 .pcs_idle_blkd_evts = ARRAY_SIZE(telem_apl_pcs_idle_blkd_data),
309 .pcs_s0ix_blkd_evts = TELEM_EVT_LEN(telem_apl_pcs_s0ix_blkd_data), 305 .pcs_s0ix_blkd_evts = ARRAY_SIZE(telem_apl_pcs_s0ix_blkd_data),
310 .pss_ltr_evts = TELEM_EVT_LEN(telem_apl_pss_ltr_data), 306 .pss_ltr_evts = ARRAY_SIZE(telem_apl_pss_ltr_data),
311 .pss_wakeup_evts = TELEM_EVT_LEN(telem_apl_pss_wakeup), 307 .pss_wakeup_evts = ARRAY_SIZE(telem_apl_pss_wakeup),
312 .ioss_d0ix_evts = TELEM_EVT_LEN(telem_apl_ioss_d0ix_data), 308 .ioss_d0ix_evts = ARRAY_SIZE(telem_apl_ioss_d0ix_data),
313 .ioss_pg_evts = TELEM_EVT_LEN(telem_apl_ioss_pg_data), 309 .ioss_pg_evts = ARRAY_SIZE(telem_apl_ioss_pg_data),
314 310
315 .pstates_id = TELEM_APL_PSS_PSTATES_ID, 311 .pstates_id = TELEM_APL_PSS_PSTATES_ID,
316 .pss_idle_id = TELEM_APL_PSS_IDLE_ID, 312 .pss_idle_id = TELEM_APL_PSS_IDLE_ID,
diff --git a/drivers/platform/x86/intel_telemetry_pltdrv.c b/drivers/platform/x86/intel_telemetry_pltdrv.c
index e0424d5a795a..2f889d6c270e 100644
--- a/drivers/platform/x86/intel_telemetry_pltdrv.c
+++ b/drivers/platform/x86/intel_telemetry_pltdrv.c
@@ -16,15 +16,9 @@
16 * It used the PUNIT and PMC IPC interfaces for configuring the counters. 16 * It used the PUNIT and PMC IPC interfaces for configuring the counters.
17 * The accumulated results are fetched from SRAM. 17 * The accumulated results are fetched from SRAM.
18 */ 18 */
19#include <linux/module.h> 19
20#include <linux/init.h>
21#include <linux/device.h>
22#include <linux/debugfs.h>
23#include <linux/seq_file.h>
24#include <linux/io.h> 20#include <linux/io.h>
25#include <linux/uaccess.h> 21#include <linux/module.h>
26#include <linux/pci.h>
27#include <linux/suspend.h>
28#include <linux/platform_device.h> 22#include <linux/platform_device.h>
29 23
30#include <asm/cpu_device_id.h> 24#include <asm/cpu_device_id.h>
@@ -256,7 +250,7 @@ static int telemetry_check_evtid(enum telemetry_unit telem_unit,
256 break; 250 break;
257 251
258 default: 252 default:
259 pr_err("Unknown Telemetry action Specified %d\n", action); 253 pr_err("Unknown Telemetry action specified %d\n", action);
260 return -EINVAL; 254 return -EINVAL;
261 } 255 }
262 256
@@ -659,7 +653,7 @@ static int telemetry_setup(struct platform_device *pdev)
659 ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig, 653 ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig,
660 TELEM_RESET); 654 TELEM_RESET);
661 if (ret) { 655 if (ret) {
662 dev_err(&pdev->dev, "TELEMTRY Setup Failed\n"); 656 dev_err(&pdev->dev, "TELEMETRY Setup Failed\n");
663 return ret; 657 return ret;
664 } 658 }
665 return 0; 659 return 0;
@@ -685,7 +679,7 @@ static int telemetry_plt_update_events(struct telemetry_evtconfig pss_evtconfig,
685 ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig, 679 ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig,
686 TELEM_UPDATE); 680 TELEM_UPDATE);
687 if (ret) 681 if (ret)
688 pr_err("TELEMTRY Config Failed\n"); 682 pr_err("TELEMETRY Config Failed\n");
689 683
690 return ret; 684 return ret;
691} 685}
@@ -822,7 +816,7 @@ static int telemetry_plt_reset_events(void)
822 ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig, 816 ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig,
823 TELEM_RESET); 817 TELEM_RESET);
824 if (ret) 818 if (ret)
825 pr_err("TELEMTRY Reset Failed\n"); 819 pr_err("TELEMETRY Reset Failed\n");
826 820
827 return ret; 821 return ret;
828} 822}
@@ -885,7 +879,7 @@ static int telemetry_plt_add_events(u8 num_pss_evts, u8 num_ioss_evts,
885 ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig, 879 ret = telemetry_setup_evtconfig(pss_evtconfig, ioss_evtconfig,
886 TELEM_ADD); 880 TELEM_ADD);
887 if (ret) 881 if (ret)
888 pr_err("TELEMTRY ADD Failed\n"); 882 pr_err("TELEMETRY ADD Failed\n");
889 883
890 return ret; 884 return ret;
891} 885}
@@ -1195,7 +1189,7 @@ static int telemetry_pltdrv_probe(struct platform_device *pdev)
1195 1189
1196 ret = telemetry_set_pltdata(&telm_pltops, telm_conf); 1190 ret = telemetry_set_pltdata(&telm_pltops, telm_conf);
1197 if (ret) { 1191 if (ret) {
1198 dev_err(&pdev->dev, "TELEMTRY Set Pltops Failed.\n"); 1192 dev_err(&pdev->dev, "TELEMETRY Set Pltops Failed.\n");
1199 goto out; 1193 goto out;
1200 } 1194 }
1201 1195
@@ -1210,7 +1204,7 @@ out:
1210 iounmap(telm_conf->pss_config.regmap); 1204 iounmap(telm_conf->pss_config.regmap);
1211 if (telm_conf->ioss_config.regmap) 1205 if (telm_conf->ioss_config.regmap)
1212 iounmap(telm_conf->ioss_config.regmap); 1206 iounmap(telm_conf->ioss_config.regmap);
1213 dev_err(&pdev->dev, "TELEMTRY Setup Failed.\n"); 1207 dev_err(&pdev->dev, "TELEMETRY Setup Failed.\n");
1214 1208
1215 return ret; 1209 return ret;
1216} 1210}
@@ -1234,7 +1228,6 @@ static struct platform_driver telemetry_soc_driver = {
1234 1228
1235static int __init telemetry_module_init(void) 1229static int __init telemetry_module_init(void)
1236{ 1230{
1237 pr_info(DRIVER_NAME ": version %s loaded\n", DRIVER_VERSION);
1238 return platform_driver_register(&telemetry_soc_driver); 1231 return platform_driver_register(&telemetry_soc_driver);
1239} 1232}
1240 1233
diff --git a/drivers/platform/x86/intel_turbo_max_3.c b/drivers/platform/x86/intel_turbo_max_3.c
index 4f60d8e32a0a..d4ea01805879 100644
--- a/drivers/platform/x86/intel_turbo_max_3.c
+++ b/drivers/platform/x86/intel_turbo_max_3.c
@@ -125,6 +125,7 @@ static int itmt_legacy_cpu_online(unsigned int cpu)
125 125
126static const struct x86_cpu_id itmt_legacy_cpu_ids[] = { 126static const struct x86_cpu_id itmt_legacy_cpu_ids[] = {
127 ICPU(INTEL_FAM6_BROADWELL_X), 127 ICPU(INTEL_FAM6_BROADWELL_X),
128 ICPU(INTEL_FAM6_SKYLAKE_X),
128 {} 129 {}
129}; 130};
130 131
diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c
index 4f3de2a8c4df..504256c3660d 100644
--- a/drivers/platform/x86/mlx-platform.c
+++ b/drivers/platform/x86/mlx-platform.c
@@ -216,8 +216,8 @@ static struct resource mlxplat_mlxcpld_resources[] = {
216 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxcpld-hotplug"), 216 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxcpld-hotplug"),
217}; 217};
218 218
219struct platform_device *mlxplat_dev; 219static struct platform_device *mlxplat_dev;
220struct mlxcpld_hotplug_platform_data *mlxplat_hotplug; 220static struct mlxcpld_hotplug_platform_data *mlxplat_hotplug;
221 221
222static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) 222static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
223{ 223{
diff --git a/drivers/platform/x86/peaq-wmi.c b/drivers/platform/x86/peaq-wmi.c
index bc98ef95514a..9b9e1f39bbfb 100644
--- a/drivers/platform/x86/peaq-wmi.c
+++ b/drivers/platform/x86/peaq-wmi.c
@@ -8,6 +8,7 @@
8 */ 8 */
9 9
10#include <linux/acpi.h> 10#include <linux/acpi.h>
11#include <linux/dmi.h>
11#include <linux/input-polldev.h> 12#include <linux/input-polldev.h>
12#include <linux/kernel.h> 13#include <linux/kernel.h>
13#include <linux/module.h> 14#include <linux/module.h>
@@ -64,8 +65,23 @@ static void peaq_wmi_poll(struct input_polled_dev *dev)
64 } 65 }
65} 66}
66 67
68/* Some other devices (Shuttle XS35) use the same WMI GUID for other purposes */
69static const struct dmi_system_id peaq_dmi_table[] __initconst = {
70 {
71 .matches = {
72 DMI_MATCH(DMI_SYS_VENDOR, "PEAQ"),
73 DMI_MATCH(DMI_PRODUCT_NAME, "PEAQ PMM C1010 MD99187"),
74 },
75 },
76 {}
77};
78
67static int __init peaq_wmi_init(void) 79static int __init peaq_wmi_init(void)
68{ 80{
81 /* WMI GUID is not unique, also check for a DMI match */
82 if (!dmi_check_system(peaq_dmi_table))
83 return -ENODEV;
84
69 if (!wmi_has_guid(PEAQ_DOLBY_BUTTON_GUID)) 85 if (!wmi_has_guid(PEAQ_DOLBY_BUTTON_GUID))
70 return -ENODEV; 86 return -ENODEV;
71 87
@@ -86,9 +102,6 @@ static int __init peaq_wmi_init(void)
86 102
87static void __exit peaq_wmi_exit(void) 103static void __exit peaq_wmi_exit(void)
88{ 104{
89 if (!wmi_has_guid(PEAQ_DOLBY_BUTTON_GUID))
90 return;
91
92 input_unregister_polled_device(peaq_poll_dev); 105 input_unregister_polled_device(peaq_poll_dev);
93} 106}
94 107
diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c
index 1157a7b646d6..266535c2a72f 100644
--- a/drivers/platform/x86/silead_dmi.c
+++ b/drivers/platform/x86/silead_dmi.c
@@ -58,6 +58,7 @@ static const struct property_entry dexp_ursus_7w_props[] = {
58 PROPERTY_ENTRY_U32("touchscreen-size-y", 630), 58 PROPERTY_ENTRY_U32("touchscreen-size-y", 630),
59 PROPERTY_ENTRY_STRING("firmware-name", "gsl1686-dexp-ursus-7w.fw"), 59 PROPERTY_ENTRY_STRING("firmware-name", "gsl1686-dexp-ursus-7w.fw"),
60 PROPERTY_ENTRY_U32("silead,max-fingers", 10), 60 PROPERTY_ENTRY_U32("silead,max-fingers", 10),
61 PROPERTY_ENTRY_BOOL("silead,home-button"),
61 { } 62 { }
62}; 63};
63 64
@@ -72,6 +73,7 @@ static const struct property_entry surftab_wintron70_st70416_6_props[] = {
72 PROPERTY_ENTRY_STRING("firmware-name", 73 PROPERTY_ENTRY_STRING("firmware-name",
73 "gsl1686-surftab-wintron70-st70416-6.fw"), 74 "gsl1686-surftab-wintron70-st70416-6.fw"),
74 PROPERTY_ENTRY_U32("silead,max-fingers", 10), 75 PROPERTY_ENTRY_U32("silead,max-fingers", 10),
76 PROPERTY_ENTRY_BOOL("silead,home-button"),
75 { } 77 { }
76}; 78};
77 79
@@ -83,6 +85,8 @@ static const struct silead_ts_dmi_data surftab_wintron70_st70416_6_data = {
83static const struct property_entry gp_electronic_t701_props[] = { 85static const struct property_entry gp_electronic_t701_props[] = {
84 PROPERTY_ENTRY_U32("touchscreen-size-x", 960), 86 PROPERTY_ENTRY_U32("touchscreen-size-x", 960),
85 PROPERTY_ENTRY_U32("touchscreen-size-y", 640), 87 PROPERTY_ENTRY_U32("touchscreen-size-y", 640),
88 PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
89 PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
86 PROPERTY_ENTRY_STRING("firmware-name", 90 PROPERTY_ENTRY_STRING("firmware-name",
87 "gsl1680-gp-electronic-t701.fw"), 91 "gsl1680-gp-electronic-t701.fw"),
88 { } 92 { }
@@ -114,6 +118,7 @@ static const struct property_entry pov_mobii_wintab_p800w_props[] = {
114 PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), 118 PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
115 PROPERTY_ENTRY_STRING("firmware-name", 119 PROPERTY_ENTRY_STRING("firmware-name",
116 "gsl3692-pov-mobii-wintab-p800w.fw"), 120 "gsl3692-pov-mobii-wintab-p800w.fw"),
121 PROPERTY_ENTRY_BOOL("silead,home-button"),
117 { } 122 { }
118}; 123};
119 124
@@ -136,6 +141,36 @@ static const struct silead_ts_dmi_data itworks_tw891_data = {
136 .properties = itworks_tw891_props, 141 .properties = itworks_tw891_props,
137}; 142};
138 143
144static const struct property_entry chuwi_hi8_pro_props[] = {
145 PROPERTY_ENTRY_U32("touchscreen-size-x", 1728),
146 PROPERTY_ENTRY_U32("touchscreen-size-y", 1148),
147 PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
148 PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-chuwi-hi8-pro.fw"),
149 PROPERTY_ENTRY_BOOL("silead,home-button"),
150 { }
151};
152
153static const struct silead_ts_dmi_data chuwi_hi8_pro_data = {
154 .acpi_name = "MSSL1680:00",
155 .properties = chuwi_hi8_pro_props,
156};
157
158static const struct property_entry digma_citi_e200_props[] = {
159 PROPERTY_ENTRY_U32("touchscreen-size-x", 1980),
160 PROPERTY_ENTRY_U32("touchscreen-size-y", 1500),
161 PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
162 PROPERTY_ENTRY_STRING("firmware-name",
163 "gsl1686-digma_citi_e200.fw"),
164 PROPERTY_ENTRY_U32("silead,max-fingers", 10),
165 PROPERTY_ENTRY_BOOL("silead,home-button"),
166 { }
167};
168
169static const struct silead_ts_dmi_data digma_citi_e200_data = {
170 .acpi_name = "MSSL1680:00",
171 .properties = digma_citi_e200_props,
172};
173
139static const struct dmi_system_id silead_ts_dmi_table[] = { 174static const struct dmi_system_id silead_ts_dmi_table[] = {
140 { 175 {
141 /* CUBE iwork8 Air */ 176 /* CUBE iwork8 Air */
@@ -219,6 +254,23 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
219 DMI_MATCH(DMI_PRODUCT_NAME, "TW891"), 254 DMI_MATCH(DMI_PRODUCT_NAME, "TW891"),
220 }, 255 },
221 }, 256 },
257 {
258 /* Chuwi Hi8 Pro */
259 .driver_data = (void *)&chuwi_hi8_pro_data,
260 .matches = {
261 DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"),
262 DMI_MATCH(DMI_PRODUCT_NAME, "X1D3_C806N"),
263 },
264 },
265 {
266 /* Digma Citi E200 */
267 .driver_data = (void *)&digma_citi_e200_data,
268 .matches = {
269 DMI_MATCH(DMI_SYS_VENDOR, "Digma"),
270 DMI_MATCH(DMI_PRODUCT_NAME, "CITI E200"),
271 DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
272 },
273 },
222 { }, 274 { },
223}; 275};
224 276
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index a16cea2be9c3..62aa2c37b8d2 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1627,7 +1627,7 @@ static const struct rfkill_ops sony_rfkill_ops = {
1627static int sony_nc_setup_rfkill(struct acpi_device *device, 1627static int sony_nc_setup_rfkill(struct acpi_device *device,
1628 enum sony_nc_rfkill nc_type) 1628 enum sony_nc_rfkill nc_type)
1629{ 1629{
1630 int err = 0; 1630 int err;
1631 struct rfkill *rfk; 1631 struct rfkill *rfk;
1632 enum rfkill_type type; 1632 enum rfkill_type type;
1633 const char *name; 1633 const char *name;
@@ -1660,17 +1660,19 @@ static int sony_nc_setup_rfkill(struct acpi_device *device,
1660 if (!rfk) 1660 if (!rfk)
1661 return -ENOMEM; 1661 return -ENOMEM;
1662 1662
1663 if (sony_call_snc_handle(sony_rfkill_handle, 0x200, &result) < 0) { 1663 err = sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
1664 if (err < 0) {
1664 rfkill_destroy(rfk); 1665 rfkill_destroy(rfk);
1665 return -1; 1666 return err;
1666 } 1667 }
1667 hwblock = !(result & 0x1); 1668 hwblock = !(result & 0x1);
1668 1669
1669 if (sony_call_snc_handle(sony_rfkill_handle, 1670 err = sony_call_snc_handle(sony_rfkill_handle,
1670 sony_rfkill_address[nc_type], 1671 sony_rfkill_address[nc_type],
1671 &result) < 0) { 1672 &result);
1673 if (err < 0) {
1672 rfkill_destroy(rfk); 1674 rfkill_destroy(rfk);
1673 return -1; 1675 return err;
1674 } 1676 }
1675 swblock = !(result & 0x2); 1677 swblock = !(result & 0x2);
1676 1678
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 3887dfeafc96..117be48ff4de 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -310,8 +310,7 @@ static struct {
310 enum { 310 enum {
311 TP_HOTKEY_TABLET_NONE = 0, 311 TP_HOTKEY_TABLET_NONE = 0,
312 TP_HOTKEY_TABLET_USES_MHKG, 312 TP_HOTKEY_TABLET_USES_MHKG,
313 /* X1 Yoga 2016, seen on BIOS N1FET44W */ 313 TP_HOTKEY_TABLET_USES_GMMS,
314 TP_HOTKEY_TABLET_USES_CMMD,
315 } hotkey_tablet; 314 } hotkey_tablet;
316 u32 kbdlight:1; 315 u32 kbdlight:1;
317 u32 light:1; 316 u32 light:1;
@@ -2044,8 +2043,28 @@ static void hotkey_poll_setup(const bool may_warn);
2044 2043
2045/* HKEY.MHKG() return bits */ 2044/* HKEY.MHKG() return bits */
2046#define TP_HOTKEY_TABLET_MASK (1 << 3) 2045#define TP_HOTKEY_TABLET_MASK (1 << 3)
2047/* ThinkPad X1 Yoga (2016) */ 2046enum {
2048#define TP_EC_CMMD_TABLET_MODE 0x6 2047 TP_ACPI_MULTI_MODE_INVALID = 0,
2048 TP_ACPI_MULTI_MODE_UNKNOWN = 1 << 0,
2049 TP_ACPI_MULTI_MODE_LAPTOP = 1 << 1,
2050 TP_ACPI_MULTI_MODE_TABLET = 1 << 2,
2051 TP_ACPI_MULTI_MODE_FLAT = 1 << 3,
2052 TP_ACPI_MULTI_MODE_STAND = 1 << 4,
2053 TP_ACPI_MULTI_MODE_TENT = 1 << 5,
2054 TP_ACPI_MULTI_MODE_STAND_TENT = 1 << 6,
2055};
2056
2057enum {
2058 /* The following modes are considered tablet mode for the purpose of
2059 * reporting the status to userspace. i.e. in all these modes it makes
2060 * sense to disable the laptop input devices such as touchpad and
2061 * keyboard.
2062 */
2063 TP_ACPI_MULTI_MODE_TABLET_LIKE = TP_ACPI_MULTI_MODE_TABLET |
2064 TP_ACPI_MULTI_MODE_STAND |
2065 TP_ACPI_MULTI_MODE_TENT |
2066 TP_ACPI_MULTI_MODE_STAND_TENT,
2067};
2049 2068
2050static int hotkey_get_wlsw(void) 2069static int hotkey_get_wlsw(void)
2051{ 2070{
@@ -2066,6 +2085,90 @@ static int hotkey_get_wlsw(void)
2066 return (status) ? TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; 2085 return (status) ? TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
2067} 2086}
2068 2087
2088static int hotkey_gmms_get_tablet_mode(int s, int *has_tablet_mode)
2089{
2090 int type = (s >> 16) & 0xffff;
2091 int value = s & 0xffff;
2092 int mode = TP_ACPI_MULTI_MODE_INVALID;
2093 int valid_modes = 0;
2094
2095 if (has_tablet_mode)
2096 *has_tablet_mode = 0;
2097
2098 switch (type) {
2099 case 1:
2100 valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
2101 TP_ACPI_MULTI_MODE_TABLET |
2102 TP_ACPI_MULTI_MODE_STAND_TENT;
2103 break;
2104 case 2:
2105 valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
2106 TP_ACPI_MULTI_MODE_FLAT |
2107 TP_ACPI_MULTI_MODE_TABLET |
2108 TP_ACPI_MULTI_MODE_STAND |
2109 TP_ACPI_MULTI_MODE_TENT;
2110 break;
2111 case 3:
2112 valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
2113 TP_ACPI_MULTI_MODE_FLAT;
2114 break;
2115 case 4:
2116 valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
2117 TP_ACPI_MULTI_MODE_TABLET |
2118 TP_ACPI_MULTI_MODE_STAND |
2119 TP_ACPI_MULTI_MODE_TENT;
2120 break;
2121 case 5:
2122 valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
2123 TP_ACPI_MULTI_MODE_FLAT |
2124 TP_ACPI_MULTI_MODE_TABLET |
2125 TP_ACPI_MULTI_MODE_STAND |
2126 TP_ACPI_MULTI_MODE_TENT;
2127 break;
2128 default:
2129 pr_err("Unknown multi mode status type %d with value 0x%04X, please report this to %s\n",
2130 type, value, TPACPI_MAIL);
2131 return 0;
2132 }
2133
2134 if (has_tablet_mode && (valid_modes & TP_ACPI_MULTI_MODE_TABLET_LIKE))
2135 *has_tablet_mode = 1;
2136
2137 switch (value) {
2138 case 1:
2139 mode = TP_ACPI_MULTI_MODE_LAPTOP;
2140 break;
2141 case 2:
2142 mode = TP_ACPI_MULTI_MODE_FLAT;
2143 break;
2144 case 3:
2145 mode = TP_ACPI_MULTI_MODE_TABLET;
2146 break;
2147 case 4:
2148 if (type == 1)
2149 mode = TP_ACPI_MULTI_MODE_STAND_TENT;
2150 else
2151 mode = TP_ACPI_MULTI_MODE_STAND;
2152 break;
2153 case 5:
2154 mode = TP_ACPI_MULTI_MODE_TENT;
2155 break;
2156 default:
2157 if (type == 5 && value == 0xffff) {
2158 pr_warn("Multi mode status is undetected, assuming laptop\n");
2159 return 0;
2160 }
2161 }
2162
2163 if (!(mode & valid_modes)) {
2164 pr_err("Unknown/reserved multi mode value 0x%04X for type %d, please report this to %s\n",
2165 value, type, TPACPI_MAIL);
2166 return 0;
2167 }
2168
2169 return !!(mode & TP_ACPI_MULTI_MODE_TABLET_LIKE);
2170}
2171
2069static int hotkey_get_tablet_mode(int *status) 2172static int hotkey_get_tablet_mode(int *status)
2070{ 2173{
2071 int s; 2174 int s;
@@ -2077,11 +2180,11 @@ static int hotkey_get_tablet_mode(int *status)
2077 2180
2078 *status = ((s & TP_HOTKEY_TABLET_MASK) != 0); 2181 *status = ((s & TP_HOTKEY_TABLET_MASK) != 0);
2079 break; 2182 break;
2080 case TP_HOTKEY_TABLET_USES_CMMD: 2183 case TP_HOTKEY_TABLET_USES_GMMS:
2081 if (!acpi_evalf(ec_handle, &s, "CMMD", "d")) 2184 if (!acpi_evalf(hkey_handle, &s, "GMMS", "dd", 0))
2082 return -EIO; 2185 return -EIO;
2083 2186
2084 *status = (s == TP_EC_CMMD_TABLET_MODE); 2187 *status = hotkey_gmms_get_tablet_mode(s, NULL);
2085 break; 2188 break;
2086 default: 2189 default:
2087 break; 2190 break;
@@ -3113,16 +3216,19 @@ static int hotkey_init_tablet_mode(void)
3113 int in_tablet_mode = 0, res; 3216 int in_tablet_mode = 0, res;
3114 char *type = NULL; 3217 char *type = NULL;
3115 3218
3116 if (acpi_evalf(hkey_handle, &res, "MHKG", "qd")) { 3219 if (acpi_evalf(hkey_handle, &res, "GMMS", "qdd", 0)) {
3220 int has_tablet_mode;
3221
3222 in_tablet_mode = hotkey_gmms_get_tablet_mode(res,
3223 &has_tablet_mode);
3224 if (has_tablet_mode)
3225 tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_GMMS;
3226 type = "GMMS";
3227 } else if (acpi_evalf(hkey_handle, &res, "MHKG", "qd")) {
3117 /* For X41t, X60t, X61t Tablets... */ 3228 /* For X41t, X60t, X61t Tablets... */
3118 tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_MHKG; 3229 tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_MHKG;
3119 in_tablet_mode = !!(res & TP_HOTKEY_TABLET_MASK); 3230 in_tablet_mode = !!(res & TP_HOTKEY_TABLET_MASK);
3120 type = "MHKG"; 3231 type = "MHKG";
3121 } else if (acpi_evalf(ec_handle, &res, "CMMD", "qd")) {
3122 /* For X1 Yoga (2016) */
3123 tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_CMMD;
3124 in_tablet_mode = res == TP_EC_CMMD_TABLET_MODE;
3125 type = "CMMD";
3126 } 3232 }
3127 3233
3128 if (!tp_features.hotkey_tablet) 3234 if (!tp_features.hotkey_tablet)
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index 0765b1797d4c..791449a2370f 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -33,17 +33,20 @@
33 33
34#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 34#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
35 35
36#include <linux/kernel.h> 36#include <linux/acpi.h>
37#include <linux/init.h>
38#include <linux/types.h>
39#include <linux/device.h> 37#include <linux/device.h>
38#include <linux/init.h>
39#include <linux/kernel.h>
40#include <linux/list.h> 40#include <linux/list.h>
41#include <linux/acpi.h> 41#include <linux/miscdevice.h>
42#include <linux/slab.h>
43#include <linux/module.h> 42#include <linux/module.h>
44#include <linux/platform_device.h> 43#include <linux/platform_device.h>
45#include <linux/wmi.h> 44#include <linux/slab.h>
45#include <linux/types.h>
46#include <linux/uaccess.h>
46#include <linux/uuid.h> 47#include <linux/uuid.h>
48#include <linux/wmi.h>
49#include <uapi/linux/wmi.h>
47 50
48ACPI_MODULE_NAME("wmi"); 51ACPI_MODULE_NAME("wmi");
49MODULE_AUTHOR("Carlos Corbacho"); 52MODULE_AUTHOR("Carlos Corbacho");
@@ -69,9 +72,12 @@ struct wmi_block {
69 struct wmi_device dev; 72 struct wmi_device dev;
70 struct list_head list; 73 struct list_head list;
71 struct guid_block gblock; 74 struct guid_block gblock;
75 struct miscdevice char_dev;
76 struct mutex char_mutex;
72 struct acpi_device *acpi_device; 77 struct acpi_device *acpi_device;
73 wmi_notify_handler handler; 78 wmi_notify_handler handler;
74 void *handler_data; 79 void *handler_data;
80 u64 req_buf_size;
75 81
76 bool read_takes_no_args; 82 bool read_takes_no_args;
77}; 83};
@@ -188,6 +194,25 @@ static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
188/* 194/*
189 * Exported WMI functions 195 * Exported WMI functions
190 */ 196 */
197
198/**
199 * set_required_buffer_size - Sets the buffer size needed for performing IOCTL
200 * @wdev: A wmi bus device from a driver
201 * @instance: Instance index
202 *
203 * Allocates memory needed for buffer, stores the buffer size in that memory
204 */
205int set_required_buffer_size(struct wmi_device *wdev, u64 length)
206{
207 struct wmi_block *wblock;
208
209 wblock = container_of(wdev, struct wmi_block, dev);
210 wblock->req_buf_size = length;
211
212 return 0;
213}
214EXPORT_SYMBOL_GPL(set_required_buffer_size);
215
191/** 216/**
192 * wmi_evaluate_method - Evaluate a WMI method 217 * wmi_evaluate_method - Evaluate a WMI method
193 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba 218 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
@@ -201,6 +226,28 @@ static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
201acpi_status wmi_evaluate_method(const char *guid_string, u8 instance, 226acpi_status wmi_evaluate_method(const char *guid_string, u8 instance,
202u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out) 227u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
203{ 228{
229 struct wmi_block *wblock = NULL;
230
231 if (!find_guid(guid_string, &wblock))
232 return AE_ERROR;
233 return wmidev_evaluate_method(&wblock->dev, instance, method_id,
234 in, out);
235}
236EXPORT_SYMBOL_GPL(wmi_evaluate_method);
237
238/**
239 * wmidev_evaluate_method - Evaluate a WMI method
240 * @wdev: A wmi bus device from a driver
241 * @instance: Instance index
242 * @method_id: Method ID to call
243 * &in: Buffer containing input for the method call
244 * &out: Empty buffer to return the method results
245 *
246 * Call an ACPI-WMI method
247 */
248acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance,
249 u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
250{
204 struct guid_block *block = NULL; 251 struct guid_block *block = NULL;
205 struct wmi_block *wblock = NULL; 252 struct wmi_block *wblock = NULL;
206 acpi_handle handle; 253 acpi_handle handle;
@@ -209,9 +256,7 @@ u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
209 union acpi_object params[3]; 256 union acpi_object params[3];
210 char method[5] = "WM"; 257 char method[5] = "WM";
211 258
212 if (!find_guid(guid_string, &wblock)) 259 wblock = container_of(wdev, struct wmi_block, dev);
213 return AE_ERROR;
214
215 block = &wblock->gblock; 260 block = &wblock->gblock;
216 handle = wblock->acpi_device->handle; 261 handle = wblock->acpi_device->handle;
217 262
@@ -246,7 +291,7 @@ u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
246 291
247 return status; 292 return status;
248} 293}
249EXPORT_SYMBOL_GPL(wmi_evaluate_method); 294EXPORT_SYMBOL_GPL(wmidev_evaluate_method);
250 295
251static acpi_status __query_block(struct wmi_block *wblock, u8 instance, 296static acpi_status __query_block(struct wmi_block *wblock, u8 instance,
252 struct acpi_buffer *out) 297 struct acpi_buffer *out)
@@ -348,23 +393,6 @@ union acpi_object *wmidev_block_query(struct wmi_device *wdev, u8 instance)
348} 393}
349EXPORT_SYMBOL_GPL(wmidev_block_query); 394EXPORT_SYMBOL_GPL(wmidev_block_query);
350 395
351struct wmi_device *wmidev_get_other_guid(struct wmi_device *wdev,
352 const char *guid_string)
353{
354 struct wmi_block *this_wb = container_of(wdev, struct wmi_block, dev);
355 struct wmi_block *other_wb;
356
357 if (!find_guid(guid_string, &other_wb))
358 return NULL;
359
360 if (other_wb->acpi_device != this_wb->acpi_device)
361 return NULL;
362
363 get_device(&other_wb->dev.dev);
364 return &other_wb->dev;
365}
366EXPORT_SYMBOL_GPL(wmidev_get_other_guid);
367
368/** 396/**
369 * wmi_set_block - Write to a WMI block 397 * wmi_set_block - Write to a WMI block
370 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba 398 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
@@ -761,6 +789,113 @@ static int wmi_dev_match(struct device *dev, struct device_driver *driver)
761 789
762 return 0; 790 return 0;
763} 791}
792static int wmi_char_open(struct inode *inode, struct file *filp)
793{
794 const char *driver_name = filp->f_path.dentry->d_iname;
795 struct wmi_block *wblock = NULL;
796 struct wmi_block *next = NULL;
797
798 list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
799 if (!wblock->dev.dev.driver)
800 continue;
801 if (strcmp(driver_name, wblock->dev.dev.driver->name) == 0) {
802 filp->private_data = wblock;
803 break;
804 }
805 }
806
807 if (!filp->private_data)
808 return -ENODEV;
809
810 return nonseekable_open(inode, filp);
811}
812
813static ssize_t wmi_char_read(struct file *filp, char __user *buffer,
814 size_t length, loff_t *offset)
815{
816 struct wmi_block *wblock = filp->private_data;
817
818 return simple_read_from_buffer(buffer, length, offset,
819 &wblock->req_buf_size,
820 sizeof(wblock->req_buf_size));
821}
822
823static long wmi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
824{
825 struct wmi_ioctl_buffer __user *input =
826 (struct wmi_ioctl_buffer __user *) arg;
827 struct wmi_block *wblock = filp->private_data;
828 struct wmi_ioctl_buffer *buf = NULL;
829 struct wmi_driver *wdriver = NULL;
830 int ret;
831
832 if (_IOC_TYPE(cmd) != WMI_IOC)
833 return -ENOTTY;
834
835 /* make sure we're not calling a higher instance than exists*/
836 if (_IOC_NR(cmd) >= wblock->gblock.instance_count)
837 return -EINVAL;
838
839 mutex_lock(&wblock->char_mutex);
840 buf = wblock->handler_data;
841 if (get_user(buf->length, &input->length)) {
842 dev_dbg(&wblock->dev.dev, "Read length from user failed\n");
843 ret = -EFAULT;
844 goto out_ioctl;
845 }
846 /* if it's too small, abort */
847 if (buf->length < wblock->req_buf_size) {
848 dev_err(&wblock->dev.dev,
849 "Buffer %lld too small, need at least %lld\n",
850 buf->length, wblock->req_buf_size);
851 ret = -EINVAL;
852 goto out_ioctl;
853 }
854 /* if it's too big, warn, driver will only use what is needed */
855 if (buf->length > wblock->req_buf_size)
856 dev_warn(&wblock->dev.dev,
857 "Buffer %lld is bigger than required %lld\n",
858 buf->length, wblock->req_buf_size);
859
860 /* copy the structure from userspace */
861 if (copy_from_user(buf, input, wblock->req_buf_size)) {
862 dev_dbg(&wblock->dev.dev, "Copy %llu from user failed\n",
863 wblock->req_buf_size);
864 ret = -EFAULT;
865 goto out_ioctl;
866 }
867
868 /* let the driver do any filtering and do the call */
869 wdriver = container_of(wblock->dev.dev.driver,
870 struct wmi_driver, driver);
871 if (!try_module_get(wdriver->driver.owner)) {
872 ret = -EBUSY;
873 goto out_ioctl;
874 }
875 ret = wdriver->filter_callback(&wblock->dev, cmd, buf);
876 module_put(wdriver->driver.owner);
877 if (ret)
878 goto out_ioctl;
879
880 /* return the result (only up to our internal buffer size) */
881 if (copy_to_user(input, buf, wblock->req_buf_size)) {
882 dev_dbg(&wblock->dev.dev, "Copy %llu to user failed\n",
883 wblock->req_buf_size);
884 ret = -EFAULT;
885 }
886
887out_ioctl:
888 mutex_unlock(&wblock->char_mutex);
889 return ret;
890}
891
892static const struct file_operations wmi_fops = {
893 .owner = THIS_MODULE,
894 .read = wmi_char_read,
895 .open = wmi_char_open,
896 .unlocked_ioctl = wmi_ioctl,
897 .compat_ioctl = wmi_ioctl,
898};
764 899
765static int wmi_dev_probe(struct device *dev) 900static int wmi_dev_probe(struct device *dev)
766{ 901{
@@ -768,16 +903,63 @@ static int wmi_dev_probe(struct device *dev)
768 struct wmi_driver *wdriver = 903 struct wmi_driver *wdriver =
769 container_of(dev->driver, struct wmi_driver, driver); 904 container_of(dev->driver, struct wmi_driver, driver);
770 int ret = 0; 905 int ret = 0;
906 int count;
907 char *buf;
771 908
772 if (ACPI_FAILURE(wmi_method_enable(wblock, 1))) 909 if (ACPI_FAILURE(wmi_method_enable(wblock, 1)))
773 dev_warn(dev, "failed to enable device -- probing anyway\n"); 910 dev_warn(dev, "failed to enable device -- probing anyway\n");
774 911
775 if (wdriver->probe) { 912 if (wdriver->probe) {
776 ret = wdriver->probe(dev_to_wdev(dev)); 913 ret = wdriver->probe(dev_to_wdev(dev));
777 if (ret != 0 && ACPI_FAILURE(wmi_method_enable(wblock, 0))) 914 if (ret != 0)
778 dev_warn(dev, "failed to disable device\n"); 915 goto probe_failure;
916 }
917
918 /* driver wants a character device made */
919 if (wdriver->filter_callback) {
920 /* check that required buffer size declared by driver or MOF */
921 if (!wblock->req_buf_size) {
922 dev_err(&wblock->dev.dev,
923 "Required buffer size not set\n");
924 ret = -EINVAL;
925 goto probe_failure;
926 }
927
928 count = get_order(wblock->req_buf_size);
929 wblock->handler_data = (void *)__get_free_pages(GFP_KERNEL,
930 count);
931 if (!wblock->handler_data) {
932 ret = -ENOMEM;
933 goto probe_failure;
934 }
935
936 buf = kmalloc(strlen(wdriver->driver.name) + 4, GFP_KERNEL);
937 if (!buf) {
938 ret = -ENOMEM;
939 goto probe_string_failure;
940 }
941 sprintf(buf, "wmi/%s", wdriver->driver.name);
942 wblock->char_dev.minor = MISC_DYNAMIC_MINOR;
943 wblock->char_dev.name = buf;
944 wblock->char_dev.fops = &wmi_fops;
945 wblock->char_dev.mode = 0444;
946 ret = misc_register(&wblock->char_dev);
947 if (ret) {
948 dev_warn(dev, "failed to register char dev: %d", ret);
949 ret = -ENOMEM;
950 goto probe_misc_failure;
951 }
779 } 952 }
780 953
954 return 0;
955
956probe_misc_failure:
957 kfree(buf);
958probe_string_failure:
959 kfree(wblock->handler_data);
960probe_failure:
961 if (ACPI_FAILURE(wmi_method_enable(wblock, 0)))
962 dev_warn(dev, "failed to disable device\n");
781 return ret; 963 return ret;
782} 964}
783 965
@@ -788,6 +970,13 @@ static int wmi_dev_remove(struct device *dev)
788 container_of(dev->driver, struct wmi_driver, driver); 970 container_of(dev->driver, struct wmi_driver, driver);
789 int ret = 0; 971 int ret = 0;
790 972
973 if (wdriver->filter_callback) {
974 misc_deregister(&wblock->char_dev);
975 kfree(wblock->char_dev.name);
976 free_pages((unsigned long)wblock->handler_data,
977 get_order(wblock->req_buf_size));
978 }
979
791 if (wdriver->remove) 980 if (wdriver->remove)
792 ret = wdriver->remove(dev_to_wdev(dev)); 981 ret = wdriver->remove(dev_to_wdev(dev));
793 982
@@ -844,6 +1033,7 @@ static int wmi_create_device(struct device *wmi_bus_dev,
844 1033
845 if (gblock->flags & ACPI_WMI_METHOD) { 1034 if (gblock->flags & ACPI_WMI_METHOD) {
846 wblock->dev.dev.type = &wmi_type_method; 1035 wblock->dev.dev.type = &wmi_type_method;
1036 mutex_init(&wblock->char_mutex);
847 goto out_init; 1037 goto out_init;
848 } 1038 }
849 1039
@@ -1145,7 +1335,7 @@ static int acpi_wmi_remove(struct platform_device *device)
1145 acpi_remove_address_space_handler(acpi_device->handle, 1335 acpi_remove_address_space_handler(acpi_device->handle,
1146 ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); 1336 ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
1147 wmi_free_devices(acpi_device); 1337 wmi_free_devices(acpi_device);
1148 device_unregister((struct device *)dev_get_drvdata(&device->dev)); 1338 device_destroy(&wmi_bus_class, MKDEV(0, 0));
1149 1339
1150 return 0; 1340 return 0;
1151} 1341}
@@ -1199,7 +1389,7 @@ static int acpi_wmi_probe(struct platform_device *device)
1199 return 0; 1389 return 0;
1200 1390
1201err_remove_busdev: 1391err_remove_busdev:
1202 device_unregister(wmi_bus_dev); 1392 device_destroy(&wmi_bus_class, MKDEV(0, 0));
1203 1393
1204err_remove_notify_handler: 1394err_remove_notify_handler:
1205 acpi_remove_notify_handler(acpi_device->handle, ACPI_DEVICE_NOTIFY, 1395 acpi_remove_notify_handler(acpi_device->handle, ACPI_DEVICE_NOTIFY,
@@ -1264,8 +1454,8 @@ err_unreg_class:
1264static void __exit acpi_wmi_exit(void) 1454static void __exit acpi_wmi_exit(void)
1265{ 1455{
1266 platform_driver_unregister(&acpi_wmi_driver); 1456 platform_driver_unregister(&acpi_wmi_driver);
1267 class_unregister(&wmi_bus_class);
1268 bus_unregister(&wmi_bus_type); 1457 bus_unregister(&wmi_bus_type);
1458 class_unregister(&wmi_bus_class);
1269} 1459}
1270 1460
1271subsys_initcall(acpi_wmi_init); 1461subsys_initcall(acpi_wmi_init);
diff --git a/include/linux/wmi.h b/include/linux/wmi.h
index cd0d7734dc49..4757cb5077e5 100644
--- a/include/linux/wmi.h
+++ b/include/linux/wmi.h
@@ -18,6 +18,7 @@
18 18
19#include <linux/device.h> 19#include <linux/device.h>
20#include <linux/acpi.h> 20#include <linux/acpi.h>
21#include <uapi/linux/wmi.h>
21 22
22struct wmi_device { 23struct wmi_device {
23 struct device dev; 24 struct device dev;
@@ -26,13 +27,17 @@ struct wmi_device {
26 bool setable; 27 bool setable;
27}; 28};
28 29
30/* evaluate the ACPI method associated with this device */
31extern acpi_status wmidev_evaluate_method(struct wmi_device *wdev,
32 u8 instance, u32 method_id,
33 const struct acpi_buffer *in,
34 struct acpi_buffer *out);
35
29/* Caller must kfree the result. */ 36/* Caller must kfree the result. */
30extern union acpi_object *wmidev_block_query(struct wmi_device *wdev, 37extern union acpi_object *wmidev_block_query(struct wmi_device *wdev,
31 u8 instance); 38 u8 instance);
32 39
33/* Gets another device on the same bus. Caller must put_device the result. */ 40extern int set_required_buffer_size(struct wmi_device *wdev, u64 length);
34extern struct wmi_device *wmidev_get_other_guid(struct wmi_device *wdev,
35 const char *guid_string);
36 41
37struct wmi_device_id { 42struct wmi_device_id {
38 const char *guid_string; 43 const char *guid_string;
@@ -45,6 +50,8 @@ struct wmi_driver {
45 int (*probe)(struct wmi_device *wdev); 50 int (*probe)(struct wmi_device *wdev);
46 int (*remove)(struct wmi_device *wdev); 51 int (*remove)(struct wmi_device *wdev);
47 void (*notify)(struct wmi_device *device, union acpi_object *data); 52 void (*notify)(struct wmi_device *device, union acpi_object *data);
53 long (*filter_callback)(struct wmi_device *wdev, unsigned int cmd,
54 struct wmi_ioctl_buffer *arg);
48}; 55};
49 56
50extern int __must_check __wmi_driver_register(struct wmi_driver *driver, 57extern int __must_check __wmi_driver_register(struct wmi_driver *driver,
diff --git a/include/uapi/linux/wmi.h b/include/uapi/linux/wmi.h
new file mode 100644
index 000000000000..7a92e9e3d1c0
--- /dev/null
+++ b/include/uapi/linux/wmi.h
@@ -0,0 +1,73 @@
1/*
2 * User API methods for ACPI-WMI mapping driver
3 *
4 * Copyright (C) 2017 Dell, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#ifndef _UAPI_LINUX_WMI_H
11#define _UAPI_LINUX_WMI_H
12
13#include <linux/ioctl.h>
14#include <linux/types.h>
15
16/* WMI bus will filter all WMI vendor driver requests through this IOC */
17#define WMI_IOC 'W'
18
19/* All ioctl requests through WMI should declare their size followed by
20 * relevant data objects
21 */
22struct wmi_ioctl_buffer {
23 __u64 length;
24 __u8 data[];
25};
26
27/* This structure may be modified by the firmware when we enter
28 * system management mode through SMM, hence the volatiles
29 */
30struct calling_interface_buffer {
31 __u16 cmd_class;
32 __u16 cmd_select;
33 volatile __u32 input[4];
34 volatile __u32 output[4];
35} __packed;
36
37struct dell_wmi_extensions {
38 __u32 argattrib;
39 __u32 blength;
40 __u8 data[];
41} __packed;
42
43struct dell_wmi_smbios_buffer {
44 __u64 length;
45 struct calling_interface_buffer std;
46 struct dell_wmi_extensions ext;
47} __packed;
48
49/* Whitelisted smbios class/select commands */
50#define CLASS_TOKEN_READ 0
51#define CLASS_TOKEN_WRITE 1
52#define SELECT_TOKEN_STD 0
53#define SELECT_TOKEN_BAT 1
54#define SELECT_TOKEN_AC 2
55#define CLASS_FLASH_INTERFACE 7
56#define SELECT_FLASH_INTERFACE 3
57#define CLASS_ADMIN_PROP 10
58#define SELECT_ADMIN_PROP 3
59#define CLASS_INFO 17
60#define SELECT_RFKILL 11
61#define SELECT_APP_REGISTRATION 3
62#define SELECT_DOCK 22
63
64/* whitelisted tokens */
65#define CAPSULE_EN_TOKEN 0x0461
66#define CAPSULE_DIS_TOKEN 0x0462
67#define WSMT_EN_TOKEN 0x04EC
68#define WSMT_DIS_TOKEN 0x04ED
69
70/* Dell SMBIOS calling IOCTL command used by dell-smbios-wmi */
71#define DELL_WMI_SMBIOS_CMD _IOWR(WMI_IOC, 0, struct dell_wmi_smbios_buffer)
72
73#endif
diff --git a/tools/Makefile b/tools/Makefile
index c03b4f69d5b7..be02c8b904db 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -30,6 +30,7 @@ help:
30 @echo ' usb - USB testing tools' 30 @echo ' usb - USB testing tools'
31 @echo ' virtio - vhost test module' 31 @echo ' virtio - vhost test module'
32 @echo ' vm - misc vm tools' 32 @echo ' vm - misc vm tools'
33 @echo ' wmi - WMI interface examples'
33 @echo ' x86_energy_perf_policy - Intel energy policy tool' 34 @echo ' x86_energy_perf_policy - Intel energy policy tool'
34 @echo '' 35 @echo ''
35 @echo 'You can do:' 36 @echo 'You can do:'
@@ -58,7 +59,7 @@ acpi: FORCE
58cpupower: FORCE 59cpupower: FORCE
59 $(call descend,power/$@) 60 $(call descend,power/$@)
60 61
61cgroup firewire hv guest spi usb virtio vm bpf iio gpio objtool leds: FORCE 62cgroup firewire hv guest spi usb virtio vm bpf iio gpio objtool leds wmi: FORCE
62 $(call descend,$@) 63 $(call descend,$@)
63 64
64liblockdep: FORCE 65liblockdep: FORCE
@@ -93,7 +94,7 @@ kvm_stat: FORCE
93all: acpi cgroup cpupower gpio hv firewire liblockdep \ 94all: acpi cgroup cpupower gpio hv firewire liblockdep \
94 perf selftests spi turbostat usb \ 95 perf selftests spi turbostat usb \
95 virtio vm bpf x86_energy_perf_policy \ 96 virtio vm bpf x86_energy_perf_policy \
96 tmon freefall iio objtool kvm_stat 97 tmon freefall iio objtool kvm_stat wmi
97 98
98acpi_install: 99acpi_install:
99 $(call descend,power/$(@:_install=),install) 100 $(call descend,power/$(@:_install=),install)
@@ -101,7 +102,7 @@ acpi_install:
101cpupower_install: 102cpupower_install:
102 $(call descend,power/$(@:_install=),install) 103 $(call descend,power/$(@:_install=),install)
103 104
104cgroup_install firewire_install gpio_install hv_install iio_install perf_install spi_install usb_install virtio_install vm_install bpf_install objtool_install: 105cgroup_install firewire_install gpio_install hv_install iio_install perf_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install:
105 $(call descend,$(@:_install=),install) 106 $(call descend,$(@:_install=),install)
106 107
107liblockdep_install: 108liblockdep_install:
@@ -126,7 +127,8 @@ install: acpi_install cgroup_install cpupower_install gpio_install \
126 hv_install firewire_install iio_install liblockdep_install \ 127 hv_install firewire_install iio_install liblockdep_install \
127 perf_install selftests_install turbostat_install usb_install \ 128 perf_install selftests_install turbostat_install usb_install \
128 virtio_install vm_install bpf_install x86_energy_perf_policy_install \ 129 virtio_install vm_install bpf_install x86_energy_perf_policy_install \
129 tmon_install freefall_install objtool_install kvm_stat_install 130 tmon_install freefall_install objtool_install kvm_stat_install \
131 wmi_install
130 132
131acpi_clean: 133acpi_clean:
132 $(call descend,power/acpi,clean) 134 $(call descend,power/acpi,clean)
@@ -134,7 +136,7 @@ acpi_clean:
134cpupower_clean: 136cpupower_clean:
135 $(call descend,power/cpupower,clean) 137 $(call descend,power/cpupower,clean)
136 138
137cgroup_clean hv_clean firewire_clean spi_clean usb_clean virtio_clean vm_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean: 139cgroup_clean hv_clean firewire_clean spi_clean usb_clean virtio_clean vm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean:
138 $(call descend,$(@:_clean=),clean) 140 $(call descend,$(@:_clean=),clean)
139 141
140liblockdep_clean: 142liblockdep_clean:
@@ -172,6 +174,6 @@ clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \
172 perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \ 174 perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \
173 vm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ 175 vm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \
174 freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \ 176 freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \
175 gpio_clean objtool_clean leds_clean 177 gpio_clean objtool_clean leds_clean wmi_clean
176 178
177.PHONY: FORCE 179.PHONY: FORCE
diff --git a/tools/wmi/Makefile b/tools/wmi/Makefile
new file mode 100644
index 000000000000..e664f1167388
--- /dev/null
+++ b/tools/wmi/Makefile
@@ -0,0 +1,18 @@
1PREFIX ?= /usr
2SBINDIR ?= sbin
3INSTALL ?= install
4CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include
5CC = $(CROSS_COMPILE)gcc
6
7TARGET = dell-smbios-example
8
9all: $(TARGET)
10
11%: %.c
12 $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
13
14clean:
15 $(RM) $(TARGET)
16
17install: dell-smbios-example
18 $(INSTALL) -D -m 755 $(TARGET) $(DESTDIR)$(PREFIX)/$(SBINDIR)/$(TARGET)
diff --git a/tools/wmi/dell-smbios-example.c b/tools/wmi/dell-smbios-example.c
new file mode 100644
index 000000000000..9d3bde081249
--- /dev/null
+++ b/tools/wmi/dell-smbios-example.c
@@ -0,0 +1,210 @@
1/*
2 * Sample application for SMBIOS communication over WMI interface
3 * Performs the following:
4 * - Simple cmd_class/cmd_select lookup for TPM information
5 * - Simple query of known tokens and their values
6 * - Simple activation of a token
7 *
8 * Copyright (C) 2017 Dell, Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <errno.h>
16#include <fcntl.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <sys/ioctl.h>
20#include <unistd.h>
21
22/* if uapi header isn't installed, this might not yet exist */
23#ifndef __packed
24#define __packed __attribute__((packed))
25#endif
26#include <linux/wmi.h>
27
28/* It would be better to discover these using udev, but for a simple
29 * application they're hardcoded
30 */
31static const char *ioctl_devfs = "/dev/wmi/dell-smbios";
32static const char *token_sysfs =
33 "/sys/bus/platform/devices/dell-smbios.0/tokens";
34
35static void show_buffer(struct dell_wmi_smbios_buffer *buffer)
36{
37 printf("Call: %x/%x [%x,%x,%x,%x]\nResults: [%8x,%8x,%8x,%8x]\n",
38 buffer->std.cmd_class, buffer->std.cmd_select,
39 buffer->std.input[0], buffer->std.input[1],
40 buffer->std.input[2], buffer->std.input[3],
41 buffer->std.output[0], buffer->std.output[1],
42 buffer->std.output[2], buffer->std.output[3]);
43}
44
45static int run_wmi_smbios_cmd(struct dell_wmi_smbios_buffer *buffer)
46{
47 int fd;
48 int ret;
49
50 fd = open(ioctl_devfs, O_NONBLOCK);
51 ret = ioctl(fd, DELL_WMI_SMBIOS_CMD, buffer);
52 close(fd);
53 return ret;
54}
55
56static int find_token(__u16 token, __u16 *location, __u16 *value)
57{
58 char location_sysfs[60];
59 char value_sysfs[57];
60 char buf[4096];
61 FILE *f;
62 int ret;
63
64 ret = sprintf(value_sysfs, "%s/%04x_value", token_sysfs, token);
65 if (ret < 0) {
66 printf("sprintf value failed\n");
67 return 2;
68 }
69 f = fopen(value_sysfs, "rb");
70 if (!f) {
71 printf("failed to open %s\n", value_sysfs);
72 return 2;
73 }
74 fread(buf, 1, 4096, f);
75 fclose(f);
76 *value = (__u16) strtol(buf, NULL, 16);
77
78 ret = sprintf(location_sysfs, "%s/%04x_location", token_sysfs, token);
79 if (ret < 0) {
80 printf("sprintf location failed\n");
81 return 1;
82 }
83 f = fopen(location_sysfs, "rb");
84 if (!f) {
85 printf("failed to open %s\n", location_sysfs);
86 return 2;
87 }
88 fread(buf, 1, 4096, f);
89 fclose(f);
90 *location = (__u16) strtol(buf, NULL, 16);
91
92 if (*location)
93 return 0;
94 return 2;
95}
96
97static int token_is_active(__u16 *location, __u16 *cmpvalue,
98 struct dell_wmi_smbios_buffer *buffer)
99{
100 int ret;
101
102 buffer->std.cmd_class = CLASS_TOKEN_READ;
103 buffer->std.cmd_select = SELECT_TOKEN_STD;
104 buffer->std.input[0] = *location;
105 ret = run_wmi_smbios_cmd(buffer);
106 if (ret != 0 || buffer->std.output[0] != 0)
107 return ret;
108 ret = (buffer->std.output[1] == *cmpvalue);
109 return ret;
110}
111
112static int query_token(__u16 token, struct dell_wmi_smbios_buffer *buffer)
113{
114 __u16 location;
115 __u16 value;
116 int ret;
117
118 ret = find_token(token, &location, &value);
119 if (ret != 0) {
120 printf("unable to find token %04x\n", token);
121 return 1;
122 }
123 return token_is_active(&location, &value, buffer);
124}
125
126static int activate_token(struct dell_wmi_smbios_buffer *buffer,
127 __u16 token)
128{
129 __u16 location;
130 __u16 value;
131 int ret;
132
133 ret = find_token(token, &location, &value);
134 if (ret != 0) {
135 printf("unable to find token %04x\n", token);
136 return 1;
137 }
138 buffer->std.cmd_class = CLASS_TOKEN_WRITE;
139 buffer->std.cmd_select = SELECT_TOKEN_STD;
140 buffer->std.input[0] = location;
141 buffer->std.input[1] = 1;
142 ret = run_wmi_smbios_cmd(buffer);
143 return ret;
144}
145
146static int query_buffer_size(__u64 *buffer_size)
147{
148 FILE *f;
149
150 f = fopen(ioctl_devfs, "rb");
151 if (!f)
152 return -EINVAL;
153 fread(buffer_size, sizeof(__u64), 1, f);
154 fclose(f);
155 return EXIT_SUCCESS;
156}
157
158int main(void)
159{
160 struct dell_wmi_smbios_buffer *buffer;
161 int ret;
162 __u64 value = 0;
163
164 ret = query_buffer_size(&value);
165 if (ret == EXIT_FAILURE || !value) {
166 printf("Unable to read buffer size\n");
167 goto out;
168 }
169 printf("Detected required buffer size %lld\n", value);
170
171 buffer = malloc(value);
172 if (buffer == NULL) {
173 printf("failed to alloc memory for ioctl\n");
174 ret = -ENOMEM;
175 goto out;
176 }
177 buffer->length = value;
178
179 /* simple SMBIOS call for looking up TPM info */
180 buffer->std.cmd_class = CLASS_FLASH_INTERFACE;
181 buffer->std.cmd_select = SELECT_FLASH_INTERFACE;
182 buffer->std.input[0] = 2;
183 ret = run_wmi_smbios_cmd(buffer);
184 if (ret) {
185 printf("smbios ioctl failed: %d\n", ret);
186 ret = EXIT_FAILURE;
187 goto out;
188 }
189 show_buffer(buffer);
190
191 /* query some tokens */
192 ret = query_token(CAPSULE_EN_TOKEN, buffer);
193 printf("UEFI Capsule enabled token is: %d\n", ret);
194 ret = query_token(CAPSULE_DIS_TOKEN, buffer);
195 printf("UEFI Capsule disabled token is: %d\n", ret);
196
197 /* activate UEFI capsule token if disabled */
198 if (ret) {
199 printf("Enabling UEFI capsule token");
200 if (activate_token(buffer, CAPSULE_EN_TOKEN)) {
201 printf("activate failed\n");
202 ret = -1;
203 goto out;
204 }
205 }
206 ret = EXIT_SUCCESS;
207out:
208 free(buffer);
209 return ret;
210}