Commit 61f91425 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'platform-drivers-x86-v5.11-1' of...

Merge tag 'platform-drivers-x86-v5.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86

Pull x86 platform driver updates from Hans de Goede:
 "Highlights:

   - New driver for changing BIOS settings from within Linux on Dell
     devices. This introduces a new generic sysfs API for this. Lenovo
     is working on also supporting this API on their devices

   - New Intel PMT telemetry and crashlog drivers

   - Support for SW_TABLET_MODE reporting for the acer-wmi and intel-hid
     drivers

   - Preparation work for improving support for Microsoft Surface
     hardware

   - Various fixes / improvements / quirks for the panasonic-laptop and
     others"

* tag 'platform-drivers-x86-v5.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (81 commits)
  platform/x86: ISST: Mark mmio_range_devid_0 and mmio_range_devid_1 with static keyword
  platform/x86: intel-hid: add Rocket Lake ACPI device ID
  x86/platform: classmate-laptop: add WiFi media button
  platform/x86: mlx-platform: Fix item counter assignment for MSN2700/ComEx system
  platform/x86: mlx-platform: Fix item counter assignment for MSN2700, MSN24xx systems
  tools/power/x86/intel-speed-select: Update version for v5.11
  tools/power/x86/intel-speed-select: Account for missing sysfs for die_id
  tools/power/x86/intel-speed-select: Read TRL from mailbox
  platform/x86: intel-hid: Do not create SW_TABLET_MODE input-dev when a KIOX010A ACPI dev is present
  platform/x86: intel-hid: Add alternative method to enable switches
  platform/x86: intel-hid: Add support for SW_TABLET_MODE
  platform/x86: intel-vbtn: Fix SW_TABLET_MODE always reporting 1 on some HP x360 models
  platform/x86: ISST: Change PCI device macros
  platform/x86: ISST: Allow configurable offset range
  platform/x86: ISST: Check for unaligned mmio address
  acer-wireless: send an EV_SYN/SYN_REPORT between state changes
  platform/x86: dell-wmi-sysman: work around for BIOS bug
  platform/x86: mlx-platform: remove an unused variable
  platform/x86: thinkpad_acpi: remove trailing semicolon in macro definition
  platform/x86: dell-smbios-base: Fix error return code in dell_smbios_init
  ...
parents 0f974581 0cd3f561
What: /sys/class/firmware-attributes/*/attributes/*/
Date: February 2021
KernelVersion: 5.11
Contact: Divya Bharathi <Divya.Bharathi@Dell.com>,
Mario Limonciello <mario.limonciello@dell.com>,
Prasanth KSR <prasanth.ksr@dell.com>
Description:
A sysfs interface for systems management software to enable
configuration capability on supported systems. This directory
exposes interfaces for interacting with configuration options.
Unless otherwise specified in an attribute description all attributes are optional
and will accept UTF-8 input.
type:
A file that can be read to obtain the type of attribute.
This attribute is mandatory.
The following are known types:
- enumeration: a set of pre-defined valid values
- integer: a range of numerical values
- string
All attribute types support the following values:
current_value:
A file that can be read to obtain the current
value of the <attr>.
This file can also be written to in order to update the value of a
<attr>
This attribute is mandatory.
default_value:
A file that can be read to obtain the default
value of the <attr>
display_name:
A file that can be read to obtain a user friendly
description of the at <attr>
display_name_language_code:
A file that can be read to obtain
the IETF language tag corresponding to the
"display_name" of the <attr>
"enumeration"-type specific properties:
possible_values:
A file that can be read to obtain the possible
values of the <attr>. Values are separated using
semi-colon (``;``).
"integer"-type specific properties:
min_value:
A file that can be read to obtain the lower
bound value of the <attr>
max_value:
A file that can be read to obtain the upper
bound value of the <attr>
scalar_increment:
A file that can be read to obtain the scalar value used for
increments of current_value this attribute accepts.
"string"-type specific properties:
max_length:
A file that can be read to obtain the maximum
length value of the <attr>
min_length:
A file that can be read to obtain the minimum
length value of the <attr>
Dell specific class extensions
------------------------------
On Dell systems the following additional attributes are available:
dell_modifier:
A file that can be read to obtain attribute-level
dependency rule. It says an attribute X will become read-only or
suppressed, if/if-not attribute Y is configured.
modifier rules can be in following format::
[ReadOnlyIf:<attribute>=<value>]
[ReadOnlyIfNot:<attribute>=<value>]
[SuppressIf:<attribute>=<value>]
[SuppressIfNot:<attribute>=<value>]
For example::
AutoOnFri/dell_modifier has value,
[SuppressIfNot:AutoOn=SelectDays]
This means AutoOnFri will be suppressed in BIOS setup if AutoOn
attribute is not "SelectDays" and its value will not be effective
through sysfs until this rule is met.
Enumeration attributes also support the following:
dell_value_modifier:
A file that can be read to obtain value-level dependency.
This file is similar to dell_modifier but here, an
attribute's current value will be forcefully changed based
dependent attributes value.
dell_value_modifier rules can be in following format::
<value>[ForceIf:<attribute>=<value>]
<value>[ForceIfNot:<attribute>=<value>]
For example:
LegacyOrom/dell_value_modifier has value:
Disabled[ForceIf:SecureBoot=Enabled]
This means LegacyOrom's current value will be forced to
"Disabled" in BIOS setup if SecureBoot is Enabled and its
value will not be effective through sysfs until this rule is
met.
What: /sys/class/firmware-attributes/*/authentication/
Date: February 2021
KernelVersion: 5.11
Contact: Divya Bharathi <Divya.Bharathi@Dell.com>,
Mario Limonciello <mario.limonciello@dell.com>,
Prasanth KSR <prasanth.ksr@dell.com>
Description:
Devices support various authentication mechanisms which can be exposed
as a separate configuration object.
For example a "BIOS Admin" password and "System" Password can be set,
reset or cleared using these attributes.
- An "Admin" password is used for preventing modification to the BIOS
settings.
- A "System" password is required to boot a machine.
Change in any of these two authentication methods will also generate an
uevent KOBJ_CHANGE.
is_enabled:
A file that can be read to obtain a 0/1 flag to see if
<attr> authentication is enabled.
This attribute is mandatory.
role:
The type of authentication used.
This attribute is mandatory.
Known types:
bios-admin:
Representing BIOS administrator password
power-on:
Representing a password required to use
the system
mechanism:
The means of authentication. This attribute is mandatory.
Only supported type currently is "password".
max_password_length:
A file that can be read to obtain the
maximum length of the Password
min_password_length:
A file that can be read to obtain the
minimum length of the Password
current_password:
A write only value used for privileged access such as
setting attributes when a system or admin password is set
or resetting to a new password
This attribute is mandatory when mechanism == "password".
new_password:
A write only value that when used in tandem with
current_password will reset a system or admin password.
Note, password management is session specific. If Admin password is set,
same password must be written into current_password file (required for
password-validation) and must be cleared once the session is over.
For example::
echo "password" > current_password
echo "disabled" > TouchScreen/current_value
echo "" > current_password
Drivers may emit a CHANGE uevent when a password is set or unset
userspace may check it again.
On Dell systems, if Admin password is set, then all BIOS attributes
require password validation.
What: /sys/class/firmware-attributes/*/attributes/pending_reboot
Date: February 2021
KernelVersion: 5.11
Contact: Divya Bharathi <Divya.Bharathi@Dell.com>,
Mario Limonciello <mario.limonciello@dell.com>,
Prasanth KSR <prasanth.ksr@dell.com>
Description:
A read-only attribute reads 1 if a reboot is necessary to apply
pending BIOS attribute changes. Also, an uevent_KOBJ_CHANGE is
generated when it changes to 1.
== =========================================
0 All BIOS attributes setting are current
1 A reboot is necessary to get pending BIOS
attribute changes applied
== =========================================
Note, userspace applications need to follow below steps for efficient
BIOS management,
1. Check if admin password is set. If yes, follow session method for
password management as briefed under authentication section above.
2. Before setting any attribute, check if it has any modifiers
or value_modifiers. If yes, incorporate them and then modify
attribute.
Drivers may emit a CHANGE uevent when this value changes and userspace
may check it again.
What: /sys/class/firmware-attributes/*/attributes/reset_bios
Date: February 2021
KernelVersion: 5.11
Contact: Divya Bharathi <Divya.Bharathi@Dell.com>,
Mario Limonciello <mario.limonciello@dell.com>,
Prasanth KSR <prasanth.ksr@dell.com>
Description:
This attribute can be used to reset the BIOS Configuration.
Specifically, it tells which type of reset BIOS configuration is being
requested on the host.
Reading from it returns a list of supported options encoded as:
- 'builtinsafe' (Built in safe configuration profile)
- 'lastknowngood' (Last known good saved configuration profile)
- 'factory' (Default factory settings configuration profile)
- 'custom' (Custom saved configuration profile)
The currently selected option is printed in square brackets as
shown below::
# echo "factory" > /sys/class/firmware-attributes/*/device/attributes/reset_bios
# cat /sys/class/firmware-attributes/*/device/attributes/reset_bios
# builtinsafe lastknowngood [factory] custom
Note that any changes to this attribute requires a reboot
for changes to take effect.
What: /sys/class/intel_pmt/
Date: October 2020
KernelVersion: 5.10
Contact: David Box <david.e.box@linux.intel.com>
Description:
The intel_pmt/ class directory contains information for
devices that expose hardware telemetry using Intel Platform
Monitoring Technology (PMT)
What: /sys/class/intel_pmt/telem<x>
Date: October 2020
KernelVersion: 5.10
Contact: David Box <david.e.box@linux.intel.com>
Description:
The telem<x> directory contains files describing an instance of
a PMT telemetry device that exposes hardware telemetry. Each
telem<x> directory has an associated telem file. This file
may be opened and mapped or read to access the telemetry space
of the device. The register layout of the telemetry space is
determined from an XML file that matches the PCI device id and
GUID for the device.
What: /sys/class/intel_pmt/telem<x>/telem
Date: October 2020
KernelVersion: 5.10
Contact: David Box <david.e.box@linux.intel.com>
Description:
(RO) The telemetry data for this telemetry device. This file
may be mapped or read to obtain the data.
What: /sys/class/intel_pmt/telem<x>/guid
Date: October 2020
KernelVersion: 5.10
Contact: David Box <david.e.box@linux.intel.com>
Description:
(RO) The GUID for this telemetry device. The GUID identifies
the version of the XML file for the parent device that is to
be used to get the register layout.
What: /sys/class/intel_pmt/telem<x>/size
Date: October 2020
KernelVersion: 5.10
Contact: David Box <david.e.box@linux.intel.com>
Description:
(RO) The size of telemetry region in bytes that corresponds to
the mapping size for the telem file.
What: /sys/class/intel_pmt/telem<x>/offset
Date: October 2020
KernelVersion: 5.10
Contact: David Box <david.e.box@linux.intel.com>
Description:
(RO) The offset of telemetry region in bytes that corresponds to
the mapping for the telem file.
What: /sys/class/intel_pmt/crashlog<x>
Date: October 2020
KernelVersion: 5.10
Contact: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Description:
The crashlog<x> directory contains files for configuring an
instance of a PMT crashlog device that can perform crash data
recording. Each crashlog<x> device has an associated crashlog
file. This file can be opened and mapped or read to access the
resulting crashlog buffer. The register layout for the buffer
can be determined from an XML file of specified GUID for the
parent device.
What: /sys/class/intel_pmt/crashlog<x>/crashlog
Date: October 2020
KernelVersion: 5.10
Contact: David Box <david.e.box@linux.intel.com>
Description:
(RO) The crashlog buffer for this crashlog device. This file
may be mapped or read to obtain the data.
What: /sys/class/intel_pmt/crashlog<x>/guid
Date: October 2020
KernelVersion: 5.10
Contact: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Description:
(RO) The GUID for this crashlog device. The GUID identifies the
version of the XML file for the parent device that should be
used to determine the register layout.
What: /sys/class/intel_pmt/crashlog<x>/size
Date: October 2020
KernelVersion: 5.10
Contact: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Description:
(RO) The length of the result buffer in bytes that corresponds
to the size for the crashlog buffer.
What: /sys/class/intel_pmt/crashlog<x>/offset
Date: October 2020
KernelVersion: 5.10
Contact: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Description:
(RO) The offset of the buffer in bytes that corresponds
to the mapping for the crashlog device.
What: /sys/class/intel_pmt/crashlog<x>/enable
Date: October 2020
KernelVersion: 5.10
Contact: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Description:
(RW) Boolean value controlling if the crashlog functionality
is enabled for the crashlog device.
What: /sys/class/intel_pmt/crashlog<x>/trigger
Date: October 2020
KernelVersion: 5.10
Contact: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Description:
(RW) Boolean value controlling the triggering of the crashlog
device node. When read it provides data on if the crashlog has
been triggered. When written to it can be used to either clear
the current trigger by writing false, or to trigger a new
event if the trigger is not currently set.
......@@ -929,6 +929,12 @@ L: linux-i2c@vger.kernel.org
S: Maintained
F: drivers/i2c/busses/i2c-amd-mp2*
AMD PMC DRIVER
M: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/amd-pmc.*
AMD POWERPLAY
M: Evan Quan <evan.quan@amd.com>
L: amd-gfx@lists.freedesktop.org
......@@ -5015,6 +5021,15 @@ M: Mario Limonciello <mario.limonciello@dell.com>
S: Maintained
F: drivers/platform/x86/dell-wmi-descriptor.c
DELL WMI SYSMAN DRIVER
M: Divya Bharathi <divya.bharathi@dell.com>
M: Mario Limonciello <mario.limonciello@dell.com>
M: Prasanth Ksr <prasanth.ksr@dell.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: Documentation/ABI/testing/sysfs-class-firmware-attributes
F: drivers/platform/x86/dell-wmi-sysman/
DELL WMI NOTIFICATIONS DRIVER
M: Matthew Garrett <mjg59@srcf.ucam.org>
M: Pali Rohár <pali@kernel.org>
......@@ -9077,6 +9092,12 @@ F: drivers/mfd/intel_soc_pmic*
F: include/linux/mfd/intel_msic.h
F: include/linux/mfd/intel_soc_pmic*
INTEL PMT DRIVER
M: "David E. Box" <david.e.box@linux.intel.com>
S: Maintained
F: drivers/mfd/intel_pmt.c
F: drivers/platform/x86/intel_pmt_*
INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT
M: Stanislav Yakovlev <stas.yakovlev@gmail.com>
L: linux-wireless@vger.kernel.org
......@@ -11735,11 +11756,26 @@ F: drivers/scsi/smartpqi/smartpqi*.[ch]
F: include/linux/cciss*.h
F: include/uapi/linux/cciss*.h
MICROSOFT SURFACE GPE LID SUPPORT DRIVER
M: Maximilian Luz <luzmaximilian@gmail.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/surface/surface_gpe.c
MICROSOFT SURFACE HARDWARE PLATFORM SUPPORT
M: Hans de Goede <hdegoede@redhat.com>
M: Mark Gross <mgross@linux.intel.com>
M: Maximilian Luz <luzmaximilian@gmail.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git
F: drivers/platform/surface/
MICROSOFT SURFACE PRO 3 BUTTON DRIVER
M: Chen Yu <yu.c.chen@intel.com>
L: platform-driver-x86@vger.kernel.org
S: Supported
F: drivers/platform/x86/surfacepro3_button.c
F: drivers/platform/surface/surfacepro3_button.c
MICROTEK X6 SCANNER
M: Oliver Neukum <oliver@neukum.org>
......@@ -13320,7 +13356,7 @@ F: include/trace/events/page_pool.h
F: net/core/page_pool.c
PANASONIC LAPTOP ACPI EXTRAS DRIVER
M: Harald Welte <laforge@gnumonks.org>
M: Kenneth Chan <kenneth.t.chan@gmail.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/panasonic-laptop.c
......
......@@ -682,6 +682,16 @@ config MFD_INTEL_PMC_BXT
Register and P-unit access. In addition this creates devices
for iTCO watchdog and telemetry that are part of the PMC.
config MFD_INTEL_PMT
tristate "Intel Platform Monitoring Technology (PMT) support"
depends on PCI
select MFD_CORE
help
The Intel Platform Monitoring Technology (PMT) is an interface that
provides access to hardware monitor registers. This driver supports
Telemetry, Watcher, and Crashlog PMT capabilities/devices for
platforms starting from Tiger Lake.
config MFD_IPAQ_MICRO
bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support"
depends on SA1100_H3100 || SA1100_H3600
......
......@@ -216,6 +216,7 @@ obj-$(CONFIG_MFD_INTEL_LPSS_PCI) += intel-lpss-pci.o
obj-$(CONFIG_MFD_INTEL_LPSS_ACPI) += intel-lpss-acpi.o
obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
obj-$(CONFIG_MFD_INTEL_PMC_BXT) += intel_pmc_bxt.o
obj-$(CONFIG_MFD_INTEL_PMT) += intel_pmt.o
obj-$(CONFIG_MFD_PALMAS) += palmas.o
obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* Intel Platform Monitoring Technology PMT driver
*
* Copyright (c) 2020, Intel Corporation.
* All Rights Reserved.
*
* Author: David E. Box <david.e.box@linux.intel.com>
*/
#include <linux/bits.h>
#include <linux/kernel.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/types.h>
/* Intel DVSEC capability vendor space offsets */
#define INTEL_DVSEC_ENTRIES 0xA
#define INTEL_DVSEC_SIZE 0xB
#define INTEL_DVSEC_TABLE 0xC
#define INTEL_DVSEC_TABLE_BAR(x) ((x) & GENMASK(2, 0))
#define INTEL_DVSEC_TABLE_OFFSET(x) ((x) & GENMASK(31, 3))
#define INTEL_DVSEC_ENTRY_SIZE 4
/* PMT capabilities */
#define DVSEC_INTEL_ID_TELEMETRY 2
#define DVSEC_INTEL_ID_WATCHER 3
#define DVSEC_INTEL_ID_CRASHLOG 4
struct intel_dvsec_header {
u16 length;
u16 id;
u8 num_entries;
u8 entry_size;
u8 tbir;
u32 offset;
};
enum pmt_quirks {
/* Watcher capability not supported */
PMT_QUIRK_NO_WATCHER = BIT(0),
/* Crashlog capability not supported */
PMT_QUIRK_NO_CRASHLOG = BIT(1),
/* Use shift instead of mask to read discovery table offset */
PMT_QUIRK_TABLE_SHIFT = BIT(2),
};
struct pmt_platform_info {
unsigned long quirks;
};
static const struct pmt_platform_info tgl_info = {
.quirks = PMT_QUIRK_NO_WATCHER | PMT_QUIRK_NO_CRASHLOG |
PMT_QUIRK_TABLE_SHIFT,
};
static int pmt_add_dev(struct pci_dev *pdev, struct intel_dvsec_header *header,
unsigned long quirks)
{
struct device *dev = &pdev->dev;
struct resource *res, *tmp;
struct mfd_cell *cell;
const char *name;
int count = header->num_entries;
int size = header->entry_size;
int id = header->id;
int i;
switch (id) {
case DVSEC_INTEL_ID_TELEMETRY:
name = "pmt_telemetry";
break;
case DVSEC_INTEL_ID_WATCHER:
if (quirks & PMT_QUIRK_NO_WATCHER) {
dev_info(dev, "Watcher not supported\n");
return 0;
}
name = "pmt_watcher";
break;
case DVSEC_INTEL_ID_CRASHLOG:
if (quirks & PMT_QUIRK_NO_CRASHLOG) {
dev_info(dev, "Crashlog not supported\n");
return 0;
}
name = "pmt_crashlog";
break;
default:
dev_err(dev, "Unrecognized PMT capability: %d\n", id);
return -EINVAL;
}
if (!header->num_entries || !header->entry_size) {
dev_err(dev, "Invalid count or size for %s header\n", name);
return -EINVAL;
}
cell = devm_kzalloc(dev, sizeof(*cell), GFP_KERNEL);
if (!cell)
return -ENOMEM;
res = devm_kcalloc(dev, count, sizeof(*res), GFP_KERNEL);
if (!res)
return -ENOMEM;
if (quirks & PMT_QUIRK_TABLE_SHIFT)
header->offset >>= 3;
/*
* The PMT DVSEC contains the starting offset and count for a block of
* discovery tables, each providing access to monitoring facilities for
* a section of the device. Create a resource list of these tables to
* provide to the driver.
*/
for (i = 0, tmp = res; i < count; i++, tmp++) {
tmp->start = pdev->resource[header->tbir].start +
header->offset + i * (size << 2);
tmp->end = tmp->start + (size << 2) - 1;
tmp->flags = IORESOURCE_MEM;
}
cell->resources = res;
cell->num_resources = count;
cell->name = name;
return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cell, 1, NULL, 0,
NULL);
}
static int pmt_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct pmt_platform_info *info;
unsigned long quirks = 0;
bool found_devices = false;
int ret, pos = 0;
ret = pcim_enable_device(pdev);
if (ret)
return ret;
info = (struct pmt_platform_info *)id->driver_data;
if (info)
quirks = info->quirks;
do {
struct intel_dvsec_header header;
u32 table;
u16 vid;
pos = pci_find_next_ext_capability(pdev, pos, PCI_EXT_CAP_ID_DVSEC);
if (!pos)
break;
pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER1, &vid);
if (vid != PCI_VENDOR_ID_INTEL)
continue;
pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER2,
&header.id);
pci_read_config_byte(pdev, pos + INTEL_DVSEC_ENTRIES,
&header.num_entries);
pci_read_config_byte(pdev, pos + INTEL_DVSEC_SIZE,
&header.entry_size);
pci_read_config_dword(pdev, pos + INTEL_DVSEC_TABLE,
&table);
header.tbir = INTEL_DVSEC_TABLE_BAR(table);
header.offset = INTEL_DVSEC_TABLE_OFFSET(table);
ret = pmt_add_dev(pdev, &header, quirks);
if (ret) {
dev_warn(&pdev->dev,
"Failed to add device for DVSEC id %d\n",
header.id);
continue;
}
found_devices = true;
} while (true);
if (!found_devices)
return -ENODEV;
pm_runtime_put(&pdev->dev);
pm_runtime_allow(&pdev->dev);
return 0;
}
static void pmt_pci_remove(struct pci_dev *pdev)
{
pm_runtime_forbid(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
}
#define PCI_DEVICE_ID_INTEL_PMT_ADL 0x467d
#define PCI_DEVICE_ID_INTEL_PMT_OOBMSM 0x09a7
#define PCI_DEVICE_ID_INTEL_PMT_TGL 0x9a0d
static const struct pci_device_id pmt_pci_ids[] = {
{ PCI_DEVICE_DATA(INTEL, PMT_ADL, &tgl_info) },
{ PCI_DEVICE_DATA(INTEL, PMT_OOBMSM, NULL) },
{ PCI_DEVICE_DATA(INTEL, PMT_TGL, &tgl_info) },
{ }
};
MODULE_DEVICE_TABLE(pci, pmt_pci_ids);
static struct pci_driver pmt_pci_driver = {
.name = "intel-pmt",
.id_table = pmt_pci_ids,
.probe = pmt_pci_probe,
.remove = pmt_pci_remove,
};
module_pci_driver(pmt_pci_driver);
MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
MODULE_DESCRIPTION("Intel Platform Monitoring Technology PMT driver");
MODULE_LICENSE("GPL v2");
......@@ -13,3 +13,5 @@ source "drivers/platform/chrome/Kconfig"
source "drivers/platform/mellanox/Kconfig"
source "drivers/platform/olpc/Kconfig"
source "drivers/platform/surface/Kconfig"
......@@ -9,3 +9,4 @@ obj-$(CONFIG_MIPS) += mips/
obj-$(CONFIG_OLPC_EC) += olpc/
obj-$(CONFIG_GOLDFISH) += goldfish/
obj-$(CONFIG_CHROME_PLATFORMS) += chrome/
obj-$(CONFIG_SURFACE_PLATFORMS) += surface/
......@@ -56,4 +56,14 @@ config MLXBF_BOOTCTL
to the userspace tools, to be used in conjunction with the eMMC
device driver to do necessary initial swap of the boot partition.
config MLXBF_PMC
tristate "Mellanox BlueField Performance Monitoring Counters driver"
depends on ARM64
depends on HWMON
depends on ACPI
help
Say y here to enable PMC support. The PMC driver provides access
to performance monitoring counters within various blocks in the
Mellanox BlueField SoC via a sysfs interface.
endif # MELLANOX_PLATFORM
......@@ -4,6 +4,7 @@
# Mellanox Platform-Specific Drivers
#
obj-$(CONFIG_MLXBF_BOOTCTL) += mlxbf-bootctl.o
obj-$(CONFIG_MLXBF_PMC) += mlxbf-pmc.o
obj-$(CONFIG_MLXBF_TMFIFO) += mlxbf-tmfifo.o
obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o
obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o
This diff is collapsed.
# SPDX-License-Identifier: GPL-2.0-only
#
# Microsoft Surface Platform-Specific Drivers
#
menuconfig SURFACE_PLATFORMS
bool "Microsoft Surface Platform-Specific Device Drivers"
default y
help
Say Y here to get to see options for platform-specific device drivers
for Microsoft Surface devices. This option alone does not add any
kernel code.
If you say N, all options in this submenu will be skipped and disabled.
if SURFACE_PLATFORMS
config SURFACE3_WMI
tristate "Surface 3 WMI Driver"
depends on ACPI_WMI
depends on DMI
depends on INPUT
depends on SPI
help
Say Y here if you have a Surface 3.
To compile this driver as a module, choose M here: the module will
be called surface3-wmi.
config SURFACE_3_BUTTON
tristate "Power/home/volume buttons driver for Microsoft Surface 3 tablet"
depends on ACPI && KEYBOARD_GPIO && I2C
help
This driver handles the power/home/volume buttons on the Microsoft Surface 3 tablet.
config SURFACE_3_POWER_OPREGION
tristate "Surface 3 battery platform operation region support"
depends on ACPI && I2C
help
This driver provides support for ACPI operation
region of the Surface 3 battery platform driver.
config SURFACE_GPE
tristate "Surface GPE/Lid Support Driver"
depends on ACPI
depends on DMI
help
This driver marks the GPEs related to the ACPI lid device found on
Microsoft Surface devices as wakeup sources and prepares them
accordingly. It is required on those devices to allow wake-ups from
suspend by opening the lid.
config SURFACE_PRO3_BUTTON
tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3/4 tablet"
depends on ACPI && INPUT
help
This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3/4 tablet.
endif # SURFACE_PLATFORMS
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for linux/drivers/platform/surface
# Microsoft Surface Platform-Specific Drivers
#
obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o
obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o
obj-$(CONFIG_SURFACE_3_POWER_OPREGION) += surface3_power.o
obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o
obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Surface GPE/Lid driver to enable wakeup from suspend via the lid by
* properly configuring the respective GPEs. Required for wakeup via lid on
* newer Intel-based Microsoft Surface devices.
*
* Copyright (C) 2020 Maximilian Luz <luzmaximilian@gmail.com>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/acpi.h>
#include <linux/dmi.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
/*
* Note: The GPE numbers for the lid devices found below have been obtained
* from ACPI/the DSDT table, specifically from the GPE handler for the
* lid.
*/
static const struct property_entry lid_device_props_l17[] = {
PROPERTY_ENTRY_U32("gpe", 0x17),
{},
};
static const struct property_entry lid_device_props_l4D[] = {
PROPERTY_ENTRY_U32("gpe", 0x4D),
{},
};
static const struct property_entry lid_device_props_l4F[] = {
PROPERTY_ENTRY_U32("gpe", 0x4F),
{},
};
static const struct property_entry lid_device_props_l57[] = {
PROPERTY_ENTRY_U32("gpe", 0x57),
{},
};
/*
* Note: When changing this, don't forget to check that the MODULE_ALIAS below
* still fits.
*/
static const struct dmi_system_id dmi_lid_device_table[] = {
{
.ident = "Surface Pro 4",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"),
},
.driver_data = (void *)lid_device_props_l17,
},
{
.ident = "Surface Pro 5",
.matches = {
/*
* We match for SKU here due to generic product name
* "Surface Pro".
*/
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"),
},
.driver_data = (void *)lid_device_props_l4F,
},
{
.ident = "Surface Pro 5 (LTE)",
.matches = {
/*
* We match for SKU here due to generic product name
* "Surface Pro"
*/
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"),
},
.driver_data = (void *)lid_device_props_l4F,
},
{
.ident = "Surface Pro 6",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"),
},
.driver_data = (void *)lid_device_props_l4F,
},
{
.ident = "Surface Pro 7",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 7"),
},
.driver_data = (void *)lid_device_props_l4D,
},
{
.ident = "Surface Book 1",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"),
},
.driver_data = (void *)lid_device_props_l17,
},
{
.ident = "Surface Book 2",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"),
},
.driver_data = (void *)lid_device_props_l17,
},
{
.ident = "Surface Book 3",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 3"),
},
.driver_data = (void *)lid_device_props_l4D,
},
{
.ident = "Surface Laptop 1",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"),
},
.driver_data = (void *)lid_device_props_l57,
},
{
.ident = "Surface Laptop 2",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"),
},
.driver_data = (void *)lid_device_props_l57,
},
{
.ident = "Surface Laptop 3 (Intel 13\")",
.matches = {
/*
* We match for SKU here due to different variants: The
* AMD (15") version does not rely on GPEs.
*/
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_3_1867:1868"),
},
.driver_data = (void *)lid_device_props_l4D,
},
{
.ident = "Surface Laptop 3 (Intel 15\")",
.matches = {
/*
* We match for SKU here due to different variants: The
* AMD (15") version does not rely on GPEs.
*/
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_3_1872"),
},
.driver_data = (void *)lid_device_props_l4D,
},
{ }
};
struct surface_lid_device {
u32 gpe_number;
};
static int surface_lid_enable_wakeup(struct device *dev, bool enable)
{
const struct surface_lid_device *lid = dev_get_drvdata(dev);
int action = enable ? ACPI_GPE_ENABLE : ACPI_GPE_DISABLE;
acpi_status status;
status = acpi_set_gpe_wake_mask(NULL, lid->gpe_number, action);
if (ACPI_FAILURE(status)) {
dev_err(dev, "failed to set GPE wake mask: %s\n",
acpi_format_exception(status));
return -EINVAL;
}
return 0;
}
static int surface_gpe_suspend(struct device *dev)
{
return surface_lid_enable_wakeup(dev, true);
}
static int surface_gpe_resume(struct device *dev)
{
return surface_lid_enable_wakeup(dev, false);
}
static SIMPLE_DEV_PM_OPS(surface_gpe_pm, surface_gpe_suspend, surface_gpe_resume);
static int surface_gpe_probe(struct platform_device *pdev)
{
struct surface_lid_device *lid;
u32 gpe_number;
acpi_status status;
int ret;
ret = device_property_read_u32(&pdev->dev, "gpe", &gpe_number);
if (ret) {
dev_err(&pdev->dev, "failed to read 'gpe' property: %d\n", ret);
return ret;
}
lid = devm_kzalloc(&pdev->dev, sizeof(*lid), GFP_KERNEL);
if (!lid)
return -ENOMEM;
lid->gpe_number = gpe_number;
platform_set_drvdata(pdev, lid);
status = acpi_mark_gpe_for_wake(NULL, gpe_number);
if (ACPI_FAILURE(status)) {
dev_err(&pdev->dev, "failed to mark GPE for wake: %s\n",
acpi_format_exception(status));
return -EINVAL;
}
status = acpi_enable_gpe(NULL, gpe_number);
if (ACPI_FAILURE(status)) {
dev_err(&pdev->dev, "failed to enable GPE: %s\n",
acpi_format_exception(status));
return -EINVAL;
}
ret = surface_lid_enable_wakeup(&pdev->dev, false);
if (ret)
acpi_disable_gpe(NULL, gpe_number);
return ret;
}
static int surface_gpe_remove(struct platform_device *pdev)
{
struct surface_lid_device *lid = dev_get_drvdata(&pdev->dev);
/* restore default behavior without this module */
surface_lid_enable_wakeup(&pdev->dev, false);
acpi_disable_gpe(NULL, lid->gpe_number);
return 0;
}
static struct platform_driver surface_gpe_driver = {
.probe = surface_gpe_probe,
.remove = surface_gpe_remove,
.driver = {
.name = "surface_gpe",
.pm = &surface_gpe_pm,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};
static struct platform_device *surface_gpe_device;
static int __init surface_gpe_init(void)
{
const struct dmi_system_id *match;
struct platform_device *pdev;
struct fwnode_handle *fwnode;
int status;
match = dmi_first_match(dmi_lid_device_table);
if (!match) {
pr_info("no compatible Microsoft Surface device found, exiting\n");
return -ENODEV;
}
status = platform_driver_register(&surface_gpe_driver);
if (status)
return status;
fwnode = fwnode_create_software_node(match->driver_data, NULL);
if (IS_ERR(fwnode)) {
status = PTR_ERR(fwnode);
goto err_node;
}
pdev = platform_device_alloc("surface_gpe", PLATFORM_DEVID_NONE);
if (!pdev) {
status = -ENOMEM;
goto err_alloc;
}
pdev->dev.fwnode = fwnode;
status = platform_device_add(pdev);
if (status)
goto err_add;
surface_gpe_device = pdev;
return 0;
err_add:
platform_device_put(pdev);
err_alloc:
fwnode_remove_software_node(fwnode);
err_node:
platform_driver_unregister(&surface_gpe_driver);
return status;
}
module_init(surface_gpe_init);
static void __exit surface_gpe_exit(void)
{
struct fwnode_handle *fwnode = surface_gpe_device->dev.fwnode;
platform_device_unregister(surface_gpe_device);
platform_driver_unregister(&surface_gpe_driver);
fwnode_remove_software_node(fwnode);
}
module_exit(surface_gpe_exit);
MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
MODULE_DESCRIPTION("Surface GPE/Lid Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("dmi:*:svnMicrosoftCorporation:pnSurface*:*");
......@@ -191,6 +191,20 @@ config ACER_WMI
If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M
here.
config AMD_PMC
tristate "AMD SoC PMC driver"
depends on ACPI && PCI
help
The driver provides support for AMD Power Management Controller
primarily responsible for S2Idle transactions that are driven from
a platform firmware running on SMU. This driver also provides a debug
mechanism to investigate the S2Idle transactions and failures.
Say Y or M here if you have a notebook powered by AMD RYZEN CPU/APU.
If you choose to compile this driver as a module the module will be
called amd-pmc.
config APPLE_GMUX
tristate "Apple Gmux Driver"
depends on ACPI && PCI
......@@ -441,6 +455,18 @@ config DELL_WMI
To compile this driver as a module, choose M here: the module will
be called dell-wmi.
config DELL_WMI_SYSMAN
tristate "Dell WMI-based Systems management driver"
depends on ACPI_WMI
depends on DMI
select NLS
help
This driver allows changing BIOS settings on many Dell machines from
2018 and newer without the use of any additional software.
To compile this driver as a module, choose M here: the module will
be called dell-wmi-sysman.
config DELL_WMI_DESCRIPTOR
tristate
depends on ACPI_WMI
......@@ -881,37 +907,6 @@ config INTEL_VBTN
To compile this driver as a module, choose M here: the module will
be called intel_vbtn.
config SURFACE3_WMI
tristate "Surface 3 WMI Driver"
depends on ACPI_WMI
depends on DMI
depends on INPUT
depends on SPI
help
Say Y here if you have a Surface 3.
To compile this driver as a module, choose M here: the module will
be called surface3-wmi.
config SURFACE_3_BUTTON
tristate "Power/home/volume buttons driver for Microsoft Surface 3 tablet"
depends on ACPI && KEYBOARD_GPIO && I2C
help
This driver handles the power/home/volume buttons on the Microsoft Surface 3 tablet.
config SURFACE_3_POWER_OPREGION
tristate "Surface 3 battery platform operation region support"
depends on ACPI && I2C
help
This driver provides support for ACPI operation
region of the Surface 3 battery platform driver.
config SURFACE_PRO3_BUTTON
tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3/4 tablet"
depends on ACPI && INPUT
help
This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3/4 tablet.
config MSI_LAPTOP
tristate "MSI Laptop Extras"
depends on ACPI
......@@ -1373,6 +1368,40 @@ config INTEL_PMC_CORE
- LTR Ignore
- MPHY/PLL gating status (Sunrisepoint PCH only)
config INTEL_PMT_CLASS
tristate "Intel Platform Monitoring Technology (PMT) Class driver"
help
The Intel Platform Monitoring Technology (PMT) class driver provides
the basic sysfs interface and file hierarchy uses by PMT devices.
For more information, see:
<file:Documentation/ABI/testing/sysfs-class-intel_pmt>
To compile this driver as a module, choose M here: the module
will be called intel_pmt_class.
config INTEL_PMT_TELEMETRY
tristate "Intel Platform Monitoring Technology (PMT) Telemetry driver"
select INTEL_PMT_CLASS
help
The Intel Platform Monitory Technology (PMT) Telemetry driver provides
access to hardware telemetry metrics on devices that support the
feature.
To compile this driver as a module, choose M here: the module
will be called intel_pmt_telemetry.
config INTEL_PMT_CRASHLOG
tristate "Intel Platform Monitoring Technology (PMT) Crashlog driver"
select INTEL_PMT_CLASS
help
The Intel Platform Monitoring Technology (PMT) crashlog driver provides
access to hardware crashlog capabilities on devices that support the
feature.
To compile this driver as a module, choose M here: the module
will be called intel_pmt_crashlog.
config INTEL_PUNIT_IPC
tristate "Intel P-Unit IPC Driver"
help
......
......@@ -22,6 +22,9 @@ obj-$(CONFIG_ACERHDF) += acerhdf.o
obj-$(CONFIG_ACER_WIRELESS) += acer-wireless.o
obj-$(CONFIG_ACER_WMI) += acer-wmi.o
# AMD
obj-$(CONFIG_AMD_PMC) += amd-pmc.o
# Apple
obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o
......@@ -47,6 +50,7 @@ obj-$(CONFIG_DELL_WMI) += dell-wmi.o
obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o
obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o
obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o
obj-$(CONFIG_DELL_WMI_SYSMAN) += dell-wmi-sysman/
# Fujitsu
obj-$(CONFIG_AMILO_RFKILL) += amilo-rfkill.o
......@@ -84,12 +88,6 @@ obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o
obj-$(CONFIG_INTEL_VBTN) += intel-vbtn.o
# Microsoft
obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o
obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o
obj-$(CONFIG_SURFACE_3_POWER_OPREGION) += surface3_power.o
obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
# MSI
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
obj-$(CONFIG_MSI_WMI) += msi-wmi.o
......@@ -143,6 +141,9 @@ obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o
obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o
obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o intel_pmc_core_pltdrv.o
obj-$(CONFIG_INTEL_PMT_CLASS) += intel_pmt_class.o
obj-$(CONFIG_INTEL_PMT_TELEMETRY) += intel_pmt_telemetry.o
obj-$(CONFIG_INTEL_PMT_CRASHLOG) += intel_pmt_crashlog.o
obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o
obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
obj-$(CONFIG_INTEL_SCU_PCI) += intel_scu_pcidrv.o
......
......@@ -28,6 +28,7 @@ static void acer_wireless_notify(struct acpi_device *adev, u32 event)
return;
}
input_report_key(idev, KEY_RFKILL, 1);
input_sync(idev);
input_report_key(idev, KEY_RFKILL, 0);
input_sync(idev);
}
......
......@@ -30,6 +30,7 @@
#include <linux/input/sparse-keymap.h>
#include <acpi/video.h>
ACPI_MODULE_NAME(KBUILD_MODNAME);
MODULE_AUTHOR("Carlos Corbacho");
MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
MODULE_LICENSE("GPL");
......@@ -80,7 +81,7 @@ MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
enum acer_wmi_event_ids {
WMID_HOTKEY_EVENT = 0x1,
WMID_ACCEL_EVENT = 0x5,
WMID_ACCEL_OR_KBD_DOCK_EVENT = 0x5,
};
static const struct key_entry acer_wmi_keymap[] __initconst = {
......@@ -128,7 +129,9 @@ struct event_return_value {
u8 function;
u8 key_num;
u16 device_state;
u32 reserved;
u16 reserved1;
u8 kbd_dock_state;
u8 reserved2;
} __attribute__((packed));
/*
......@@ -206,14 +209,13 @@ struct hotkey_function_type_aa {
/*
* Interface capability flags
*/
#define ACER_CAP_MAILLED (1<<0)
#define ACER_CAP_WIRELESS (1<<1)
#define ACER_CAP_BLUETOOTH (1<<2)
#define ACER_CAP_BRIGHTNESS (1<<3)
#define ACER_CAP_THREEG (1<<4)
#define ACER_CAP_ACCEL (1<<5)
#define ACER_CAP_RFBTN (1<<6)
#define ACER_CAP_ANY (0xFFFFFFFF)
#define ACER_CAP_MAILLED BIT(0)
#define ACER_CAP_WIRELESS BIT(1)
#define ACER_CAP_BLUETOOTH BIT(2)
#define ACER_CAP_BRIGHTNESS BIT(3)
#define ACER_CAP_THREEG BIT(4)
#define ACER_CAP_SET_FUNCTION_MODE BIT(5)
#define ACER_CAP_KBD_DOCK BIT(6)
/*
* Interface type flags
......@@ -236,6 +238,7 @@ static int mailled = -1;
static int brightness = -1;
static int threeg = -1;
static int force_series;
static int force_caps = -1;
static bool ec_raw_mode;
static bool has_type_aa;
static u16 commun_func_bitmap;
......@@ -245,11 +248,13 @@ module_param(mailled, int, 0444);
module_param(brightness, int, 0444);
module_param(threeg, int, 0444);
module_param(force_series, int, 0444);
module_param(force_caps, int, 0444);
module_param(ec_raw_mode, bool, 0444);
MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
MODULE_PARM_DESC(force_series, "Force a different laptop series");
MODULE_PARM_DESC(force_caps, "Force the capability bitmask to this value");
MODULE_PARM_DESC(ec_raw_mode, "Enable EC raw mode");
struct acer_data {
......@@ -303,9 +308,6 @@ static struct quirk_entry *quirks;
static void __init set_quirks(void)
{
if (!interface)
return;
if (quirks->mailled)
interface->capability |= ACER_CAP_MAILLED;
......@@ -319,6 +321,15 @@ static int __init dmi_matched(const struct dmi_system_id *dmi)
return 1;
}
static int __init set_force_caps(const struct dmi_system_id *dmi)
{
if (force_caps == -1) {
force_caps = (uintptr_t)dmi->driver_data;
pr_info("Found %s, set force_caps to 0x%x\n", dmi->ident, force_caps);
}
return 1;
}
static struct quirk_entry quirk_unknown = {
};
......@@ -497,6 +508,33 @@ static const struct dmi_system_id acer_quirks[] __initconst = {
},
.driver_data = &quirk_acer_travelmate_2490,
},
{
.callback = set_force_caps,
.ident = "Acer Aspire Switch 10E SW3-016",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW3-016"),
},
.driver_data = (void *)ACER_CAP_KBD_DOCK,
},
{
.callback = set_force_caps,
.ident = "Acer Aspire Switch 10 SW5-012",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
},
.driver_data = (void *)ACER_CAP_KBD_DOCK,
},
{
.callback = set_force_caps,
.ident = "Acer One 10 (S1003)",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "One S1003"),
},
.driver_data = (void *)ACER_CAP_KBD_DOCK,
},
{}
};
......@@ -649,8 +687,6 @@ static void __init find_quirks(void)
if (quirks == NULL)
quirks = &quirk_unknown;
set_quirks();
}
/*
......@@ -793,7 +829,6 @@ static acpi_status AMW0_set_u32(u32 value, u32 cap)
switch (quirks->brightness) {
default:
return ec_write(0x83, value);
break;
}
default:
return AE_ERROR;
......@@ -1253,10 +1288,8 @@ static void __init type_aa_dmi_decode(const struct dmi_header *header, void *d)
interface->capability |= ACER_CAP_THREEG;
if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH)
interface->capability |= ACER_CAP_BLUETOOTH;
if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_RFBTN) {
interface->capability |= ACER_CAP_RFBTN;
if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_RFBTN)
commun_func_bitmap &= ~ACER_WMID3_GDS_RFBTN;
}
commun_fn_key_number = type_aa->commun_fn_key_number;
}
......@@ -1520,7 +1553,7 @@ static int acer_gsensor_event(void)
struct acpi_buffer output;
union acpi_object out_obj[5];
if (!has_cap(ACER_CAP_ACCEL))
if (!acer_wmi_accel_dev)
return -1;
output.length = sizeof(out_obj);
......@@ -1543,6 +1576,71 @@ static int acer_gsensor_event(void)
return 0;
}
/*
* Switch series keyboard dock status
*/
static int acer_kbd_dock_state_to_sw_tablet_mode(u8 kbd_dock_state)
{
switch (kbd_dock_state) {
case 0x01: /* Docked, traditional clamshell laptop mode */
return 0;
case 0x04: /* Stand-alone tablet */
case 0x40: /* Docked, tent mode, keyboard not usable */
return 1;
default:
pr_warn("Unknown kbd_dock_state 0x%02x\n", kbd_dock_state);
}
return 0;
}
static void acer_kbd_dock_get_initial_state(void)
{
u8 *output, input[8] = { 0x05, 0x00, };
struct acpi_buffer input_buf = { sizeof(input), input };
struct acpi_buffer output_buf = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
acpi_status status;
int sw_tablet_mode;
status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input_buf, &output_buf);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Error getting keyboard-dock initial status"));
return;
}
obj = output_buf.pointer;
if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length != 8) {
pr_err("Unexpected output format getting keyboard-dock initial status\n");
goto out_free_obj;
}
output = obj->buffer.pointer;
if (output[0] != 0x00 || (output[3] != 0x05 && output[3] != 0x45)) {
pr_err("Unexpected output [0]=0x%02x [3]=0x%02x getting keyboard-dock initial status\n",
output[0], output[3]);
goto out_free_obj;
}
sw_tablet_mode = acer_kbd_dock_state_to_sw_tablet_mode(output[4]);
input_report_switch(acer_wmi_input_dev, SW_TABLET_MODE, sw_tablet_mode);
out_free_obj:
kfree(obj);
}
static void acer_kbd_dock_event(const struct event_return_value *event)
{
int sw_tablet_mode;
if (!has_cap(ACER_CAP_KBD_DOCK))
return;
sw_tablet_mode = acer_kbd_dock_state_to_sw_tablet_mode(event->kbd_dock_state);
input_report_switch(acer_wmi_input_dev, SW_TABLET_MODE, sw_tablet_mode);
input_sync(acer_wmi_input_dev);
}
/*
* Rfkill devices
*/
......@@ -1770,8 +1868,9 @@ static void acer_wmi_notify(u32 value, void *context)
sparse_keymap_report_event(acer_wmi_input_dev, scancode, 1, true);
}
break;
case WMID_ACCEL_EVENT:
case WMID_ACCEL_OR_KBD_DOCK_EVENT:
acer_gsensor_event();
acer_kbd_dock_event(&return_value);
break;
default:
pr_warn("Unknown function number - %d - %d\n",
......@@ -1894,8 +1993,6 @@ static int __init acer_wmi_accel_setup(void)
gsensor_handle = acpi_device_handle(adev);
acpi_dev_put(adev);
interface->capability |= ACER_CAP_ACCEL;
acer_wmi_accel_dev = input_allocate_device();
if (!acer_wmi_accel_dev)
return -ENOMEM;
......@@ -1921,11 +2018,6 @@ static int __init acer_wmi_accel_setup(void)
return err;
}
static void acer_wmi_accel_destroy(void)
{
input_unregister_device(acer_wmi_accel_dev);
}
static int __init acer_wmi_input_setup(void)
{
acpi_status status;
......@@ -1943,6 +2035,9 @@ static int __init acer_wmi_input_setup(void)
if (err)
goto err_free_dev;
if (has_cap(ACER_CAP_KBD_DOCK))
input_set_capability(acer_wmi_input_dev, EV_SW, SW_TABLET_MODE);
status = wmi_install_notify_handler(ACERWMID_EVENT_GUID,
acer_wmi_notify, NULL);
if (ACPI_FAILURE(status)) {
......@@ -1950,6 +2045,9 @@ static int __init acer_wmi_input_setup(void)
goto err_free_dev;
}
if (has_cap(ACER_CAP_KBD_DOCK))
acer_kbd_dock_get_initial_state();
err = input_register_device(acer_wmi_input_dev);
if (err)
goto err_uninstall_notifier;
......@@ -2080,7 +2178,7 @@ static int acer_resume(struct device *dev)
if (has_cap(ACER_CAP_BRIGHTNESS))
set_u32(data->brightness, ACER_CAP_BRIGHTNESS);
if (has_cap(ACER_CAP_ACCEL))
if (acer_wmi_accel_dev)
acer_gsensor_init();
return 0;
......@@ -2181,7 +2279,7 @@ static int __init acer_wmi_init(void)
}
/* WMID always provides brightness methods */
interface->capability |= ACER_CAP_BRIGHTNESS;
} else if (!wmi_has_guid(WMID_GUID2) && interface && !has_type_aa) {
} else if (!wmi_has_guid(WMID_GUID2) && interface && !has_type_aa && force_caps == -1) {
pr_err("No WMID device detection method found\n");
return -ENODEV;
}
......@@ -2211,7 +2309,14 @@ static int __init acer_wmi_init(void)
if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
interface->capability &= ~ACER_CAP_BRIGHTNESS;
if (wmi_has_guid(WMID_GUID3)) {
if (wmi_has_guid(WMID_GUID3))
interface->capability |= ACER_CAP_SET_FUNCTION_MODE;
if (force_caps != -1)
interface->capability = force_caps;
if (wmi_has_guid(WMID_GUID3) &&
(interface->capability & ACER_CAP_SET_FUNCTION_MODE)) {
if (ACPI_FAILURE(acer_wmi_enable_rf_button()))
pr_warn("Cannot enable RF Button Driver\n");
......@@ -2270,8 +2375,8 @@ static int __init acer_wmi_init(void)
error_platform_register:
if (wmi_has_guid(ACERWMID_EVENT_GUID))
acer_wmi_input_destroy();
if (has_cap(ACER_CAP_ACCEL))
acer_wmi_accel_destroy();
if (acer_wmi_accel_dev)
input_unregister_device(acer_wmi_accel_dev);
return err;
}
......@@ -2281,8 +2386,8 @@ static void __exit acer_wmi_exit(void)
if (wmi_has_guid(ACERWMID_EVENT_GUID))
acer_wmi_input_destroy();
if (has_cap(ACER_CAP_ACCEL))
acer_wmi_accel_destroy();
if (acer_wmi_accel_dev)
input_unregister_device(acer_wmi_accel_dev);
remove_debugfs();
platform_device_unregister(acer_platform_device);
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* AMD SoC Power Management Controller Driver
*
* Copyright (c) 2020, Advanced Micro Devices, Inc.
* All Rights Reserved.
*
* Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/acpi.h>
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/suspend.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
/* SMU communication registers */
#define AMD_PMC_REGISTER_MESSAGE 0x538
#define AMD_PMC_REGISTER_RESPONSE 0x980
#define AMD_PMC_REGISTER_ARGUMENT 0x9BC
/* Base address of SMU for mapping physical address to virtual address */
#define AMD_PMC_SMU_INDEX_ADDRESS 0xB8
#define AMD_PMC_SMU_INDEX_DATA 0xBC
#define AMD_PMC_MAPPING_SIZE 0x01000
#define AMD_PMC_BASE_ADDR_OFFSET 0x10000
#define AMD_PMC_BASE_ADDR_LO 0x13B102E8
#define AMD_PMC_BASE_ADDR_HI 0x13B102EC
#define AMD_PMC_BASE_ADDR_LO_MASK GENMASK(15, 0)
#define AMD_PMC_BASE_ADDR_HI_MASK GENMASK(31, 20)
/* SMU Response Codes */
#define AMD_PMC_RESULT_OK 0x01
#define AMD_PMC_RESULT_CMD_REJECT_BUSY 0xFC
#define AMD_PMC_RESULT_CMD_REJECT_PREREQ 0xFD
#define AMD_PMC_RESULT_CMD_UNKNOWN 0xFE
#define AMD_PMC_RESULT_FAILED 0xFF
/* List of supported CPU ids */
#define AMD_CPU_ID_RV 0x15D0
#define AMD_CPU_ID_RN 0x1630
#define AMD_CPU_ID_PCO AMD_CPU_ID_RV
#define AMD_CPU_ID_CZN AMD_CPU_ID_RN
#define AMD_SMU_FW_VERSION 0x0
#define PMC_MSG_DELAY_MIN_US 100
#define RESPONSE_REGISTER_LOOP_MAX 200
enum amd_pmc_def {
MSG_TEST = 0x01,
MSG_OS_HINT_PCO,
MSG_OS_HINT_RN,
};
struct amd_pmc_dev {
void __iomem *regbase;
void __iomem *smu_base;
u32 base_addr;
u32 cpu_id;
struct device *dev;
#if IS_ENABLED(CONFIG_DEBUG_FS)
struct dentry *dbgfs_dir;
#endif /* CONFIG_DEBUG_FS */
};
static struct amd_pmc_dev pmc;
static inline u32 amd_pmc_reg_read(struct amd_pmc_dev *dev, int reg_offset)
{
return ioread32(dev->regbase + reg_offset);
}
static inline void amd_pmc_reg_write(struct amd_pmc_dev *dev, int reg_offset, u32 val)
{
iowrite32(val, dev->regbase + reg_offset);
}
#if CONFIG_DEBUG_FS
static int smu_fw_info_show(struct seq_file *s, void *unused)
{
struct amd_pmc_dev *dev = s->private;
u32 value;
value = ioread32(dev->smu_base + AMD_SMU_FW_VERSION);
seq_printf(s, "SMU FW Info: %x\n", value);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(smu_fw_info);
static void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev)
{
debugfs_remove_recursive(dev->dbgfs_dir);
}
static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev)
{
dev->dbgfs_dir = debugfs_create_dir("amd_pmc", NULL);
debugfs_create_file("smu_fw_info", 0644, dev->dbgfs_dir, dev,
&smu_fw_info_fops);
}
#else
static inline void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev)
{
}
static inline void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev)
{
}
#endif /* CONFIG_DEBUG_FS */
static void amd_pmc_dump_registers(struct amd_pmc_dev *dev)
{
u32 value;
value = amd_pmc_reg_read(dev, AMD_PMC_REGISTER_RESPONSE);
dev_dbg(dev->dev, "AMD_PMC_REGISTER_RESPONSE:%x\n", value);
value = amd_pmc_reg_read(dev, AMD_PMC_REGISTER_ARGUMENT);
dev_dbg(dev->dev, "AMD_PMC_REGISTER_ARGUMENT:%x\n", value);
value = amd_pmc_reg_read(dev, AMD_PMC_REGISTER_MESSAGE);
dev_dbg(dev->dev, "AMD_PMC_REGISTER_MESSAGE:%x\n", value);
}
static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set)
{
int rc;
u8 msg;
u32 val;
/* Wait until we get a valid response */
rc = readx_poll_timeout(ioread32, dev->regbase + AMD_PMC_REGISTER_RESPONSE,
val, val > 0, PMC_MSG_DELAY_MIN_US,
PMC_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX);
if (rc) {
dev_err(dev->dev, "failed to talk to SMU\n");
return rc;
}
/* Write zero to response register */
amd_pmc_reg_write(dev, AMD_PMC_REGISTER_RESPONSE, 0);
/* Write argument into response register */
amd_pmc_reg_write(dev, AMD_PMC_REGISTER_ARGUMENT, set);
/* Write message ID to message ID register */
msg = (dev->cpu_id == AMD_CPU_ID_RN) ? MSG_OS_HINT_RN : MSG_OS_HINT_PCO;
amd_pmc_reg_write(dev, AMD_PMC_REGISTER_MESSAGE, msg);
return 0;
}
static int __maybe_unused amd_pmc_suspend(struct device *dev)
{
struct amd_pmc_dev *pdev = dev_get_drvdata(dev);
int rc;
rc = amd_pmc_send_cmd(pdev, 1);
if (rc)
dev_err(pdev->dev, "suspend failed\n");
amd_pmc_dump_registers(pdev);
return 0;
}
static int __maybe_unused amd_pmc_resume(struct device *dev)
{
struct amd_pmc_dev *pdev = dev_get_drvdata(dev);
int rc;
rc = amd_pmc_send_cmd(pdev, 0);
if (rc)
dev_err(pdev->dev, "resume failed\n");
amd_pmc_dump_registers(pdev);
return 0;
}
static const struct dev_pm_ops amd_pmc_pm_ops = {
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(amd_pmc_suspend, amd_pmc_resume)
};
static const struct pci_device_id pmc_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CZN) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RN) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PCO) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RV) },
{ }
};
static int amd_pmc_probe(struct platform_device *pdev)
{
struct amd_pmc_dev *dev = &pmc;
struct pci_dev *rdev;
u32 base_addr_lo;
u32 base_addr_hi;
u64 base_addr;
int err;
u32 val;
dev->dev = &pdev->dev;
rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
if (!rdev || !pci_match_id(pmc_pci_ids, rdev))
return -ENODEV;
dev->cpu_id = rdev->device;
err = pci_write_config_dword(rdev, AMD_PMC_SMU_INDEX_ADDRESS, AMD_PMC_BASE_ADDR_LO);
if (err) {
dev_err(dev->dev, "error writing to 0x%x\n", AMD_PMC_SMU_INDEX_ADDRESS);
return pcibios_err_to_errno(err);
}
err = pci_read_config_dword(rdev, AMD_PMC_SMU_INDEX_DATA, &val);
if (err)
return pcibios_err_to_errno(err);
base_addr_lo = val & AMD_PMC_BASE_ADDR_HI_MASK;
err = pci_write_config_dword(rdev, AMD_PMC_SMU_INDEX_ADDRESS, AMD_PMC_BASE_ADDR_HI);
if (err) {
dev_err(dev->dev, "error writing to 0x%x\n", AMD_PMC_SMU_INDEX_ADDRESS);
return pcibios_err_to_errno(err);
}
err = pci_read_config_dword(rdev, AMD_PMC_SMU_INDEX_DATA, &val);
if (err)
return pcibios_err_to_errno(err);
base_addr_hi = val & AMD_PMC_BASE_ADDR_LO_MASK;
pci_dev_put(rdev);
base_addr = ((u64)base_addr_hi << 32 | base_addr_lo);
dev->smu_base = devm_ioremap(dev->dev, base_addr, AMD_PMC_MAPPING_SIZE);
if (!dev->smu_base)
return -ENOMEM;
dev->regbase = devm_ioremap(dev->dev, base_addr + AMD_PMC_BASE_ADDR_OFFSET,
AMD_PMC_MAPPING_SIZE);
if (!dev->regbase)
return -ENOMEM;
amd_pmc_dump_registers(dev);
platform_set_drvdata(pdev, dev);
amd_pmc_dbgfs_register(dev);
return 0;
}
static int amd_pmc_remove(struct platform_device *pdev)
{
struct amd_pmc_dev *dev = platform_get_drvdata(pdev);
amd_pmc_dbgfs_unregister(dev);
return 0;
}
static const struct acpi_device_id amd_pmc_acpi_ids[] = {
{"AMDI0005", 0},
{"AMD0004", 0},
{ }
};
MODULE_DEVICE_TABLE(acpi, amd_pmc_acpi_ids);
static struct platform_driver amd_pmc_driver = {
.driver = {
.name = "amd_pmc",
.acpi_match_table = amd_pmc_acpi_ids,
.pm = &amd_pmc_pm_ops,
},
.probe = amd_pmc_probe,
.remove = amd_pmc_remove,
};
module_platform_driver(amd_pmc_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("AMD PMC Driver");
......@@ -119,6 +119,11 @@ static struct quirk_entry quirk_asus_use_kbd_dock_devid = {
.use_kbd_dock_devid = true,
};
static struct quirk_entry quirk_asus_use_lid_flip_devid = {
.wmi_backlight_set_devstate = true,
.use_lid_flip_devid = true,
};
static int dmi_matched(const struct dmi_system_id *dmi)
{
pr_info("Identified laptop model '%s'\n", dmi->ident);
......@@ -520,6 +525,16 @@ static const struct dmi_system_id asus_quirks[] = {
},
.driver_data = &quirk_asus_use_kbd_dock_devid,
},
{
.callback = dmi_matched,
.ident = "ASUS ZenBook Flip UX360",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
/* Match UX360* */
DMI_MATCH(DMI_PRODUCT_NAME, "UX360"),
},
.driver_data = &quirk_asus_use_lid_flip_devid,
},
{},
};
......
......@@ -63,6 +63,7 @@ MODULE_LICENSE("GPL");
#define NOTIFY_KBD_BRTTOGGLE 0xc7
#define NOTIFY_KBD_FBM 0x99
#define NOTIFY_KBD_TTP 0xae
#define NOTIFY_LID_FLIP 0xfa
#define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0)
......@@ -375,6 +376,20 @@ static int asus_wmi_input_init(struct asus_wmi *asus)
}
}
if (asus->driver->quirks->use_lid_flip_devid) {
result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP);
if (result < 0)
asus->driver->quirks->use_lid_flip_devid = 0;
if (result >= 0) {
input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
} else if (result == -ENODEV) {
pr_err("This device has lid_flip quirk but got ENODEV checking it. This is a bug.");
} else {
pr_err("Error checking for lid-flip: %d\n", result);
}
}
err = input_register_device(asus->inputdev);
if (err)
goto err_free_dev;
......@@ -394,6 +409,18 @@ static void asus_wmi_input_exit(struct asus_wmi *asus)
asus->inputdev = NULL;
}
/* Tablet mode ****************************************************************/
static void lid_flip_tablet_mode_get_state(struct asus_wmi *asus)
{
int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP);
if (result >= 0) {
input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
input_sync(asus->inputdev);
}
}
/* Battery ********************************************************************/
/* The battery maximum charging percentage */
......@@ -1663,6 +1690,10 @@ static int fan_boost_mode_write(struct asus_wmi *asus)
pr_info("Set fan boost mode: %u\n", value);
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_FAN_BOOST_MODE, value,
&retval);
sysfs_notify(&asus->platform_device->dev.kobj, NULL,
"fan_boost_mode");
if (err) {
pr_warn("Failed to set fan boost mode: %d\n", err);
return err;
......@@ -1774,6 +1805,10 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus)
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
value, &retval);
sysfs_notify(&asus->platform_device->dev.kobj, NULL,
"throttle_thermal_policy");
if (err) {
pr_warn("Failed to set throttle thermal policy: %d\n", err);
return err;
......@@ -2128,6 +2163,11 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
return;
}
if (asus->driver->quirks->use_lid_flip_devid && code == NOTIFY_LID_FLIP) {
lid_flip_tablet_mode_get_state(asus);
return;
}
if (asus->fan_boost_mode_available && code == NOTIFY_KBD_FBM) {
fan_boost_mode_switch_next(asus);
return;
......@@ -2719,6 +2759,10 @@ static int asus_hotk_resume(struct device *device)
if (asus_wmi_has_fnlock_key(asus))
asus_wmi_fnlock_update(asus);
if (asus->driver->quirks->use_lid_flip_devid)
lid_flip_tablet_mode_get_state(asus);
return 0;
}
......@@ -2757,6 +2801,10 @@ static int asus_hotk_restore(struct device *device)
if (asus_wmi_has_fnlock_key(asus))
asus_wmi_fnlock_update(asus);
if (asus->driver->quirks->use_lid_flip_devid)
lid_flip_tablet_mode_get_state(asus);
return 0;
}
......
......@@ -34,6 +34,7 @@ struct quirk_entry {
bool wmi_backlight_set_devstate;
bool wmi_force_als_set;
bool use_kbd_dock_devid;
bool use_lid_flip_devid;
int wapf;
/*
* For machines with AMD graphic chips, it will send out WMI event
......
......@@ -1023,6 +1023,8 @@ static int cmpc_keys_codes[] = {
KEY_CAMERA,
KEY_BACK,
KEY_FORWARD,
KEY_UNKNOWN,
KEY_WLAN, /* NL3: 0x8b (press), 0x9b (release) */
KEY_MAX
};
......
......@@ -594,6 +594,7 @@ static int __init dell_smbios_init(void)
if (wmi && smm) {
pr_err("No SMBIOS backends available (wmi: %d, smm: %d)\n",
wmi, smm);
ret = -ENODEV;
goto fail_create_group;
}
......
obj-$(CONFIG_DELL_WMI_SYSMAN) += dell-wmi-sysman.o
dell-wmi-sysman-objs := sysman.o \
enum-attributes.o \
int-attributes.o \
string-attributes.o \
passobj-attributes.o \
biosattr-interface.o \
passwordattr-interface.o
// SPDX-License-Identifier: GPL-2.0
/*
* Functions corresponding to SET methods under BIOS attributes interface GUID for use
* with dell-wmi-sysman
*
* Copyright (c) 2020 Dell Inc.
*/
#include <linux/wmi.h>
#include "dell-wmi-sysman.h"
#define SETDEFAULTVALUES_METHOD_ID 0x02
#define SETBIOSDEFAULTS_METHOD_ID 0x03
#define SETATTRIBUTE_METHOD_ID 0x04
static int call_biosattributes_interface(struct wmi_device *wdev, char *in_args, size_t size,
int method_id)
{
struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
struct acpi_buffer input;
union acpi_object *obj;
acpi_status status;
int ret = -EIO;
input.length = (acpi_size) size;
input.pointer = in_args;
status = wmidev_evaluate_method(wdev, 0, method_id, &input, &output);
if (ACPI_FAILURE(status))
return -EIO;
obj = (union acpi_object *)output.pointer;
if (obj->type == ACPI_TYPE_INTEGER)
ret = obj->integer.value;
if (wmi_priv.pending_changes == 0) {
wmi_priv.pending_changes = 1;
/* let userland know it may need to check reboot pending again */
kobject_uevent(&wmi_priv.class_dev->kobj, KOBJ_CHANGE);
}
kfree(output.pointer);
return map_wmi_error(ret);
}
/**
* set_attribute() - Update an attribute value
* @a_name: The attribute name
* @a_value: The attribute value
*
* Sets an attribute to new value
*/
int set_attribute(const char *a_name, const char *a_value)
{
size_t security_area_size, buffer_size;
size_t a_name_size, a_value_size;
char *buffer = NULL, *start;
int ret;
mutex_lock(&wmi_priv.mutex);
if (!wmi_priv.bios_attr_wdev) {
ret = -ENODEV;
goto out;
}
/* build/calculate buffer */
security_area_size = calculate_security_buffer(wmi_priv.current_admin_password);
a_name_size = calculate_string_buffer(a_name);
a_value_size = calculate_string_buffer(a_value);
buffer_size = security_area_size + a_name_size + a_value_size;
buffer = kzalloc(buffer_size, GFP_KERNEL);
if (!buffer) {
ret = -ENOMEM;
goto out;
}
/* build security area */
populate_security_buffer(buffer, wmi_priv.current_admin_password);
/* build variables to set */
start = buffer + security_area_size;
ret = populate_string_buffer(start, a_name_size, a_name);
if (ret < 0)
goto out;
start += ret;
ret = populate_string_buffer(start, a_value_size, a_value);
if (ret < 0)
goto out;
print_hex_dump_bytes("set attribute data: ", DUMP_PREFIX_NONE, buffer, buffer_size);
ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev,
buffer, buffer_size,
SETATTRIBUTE_METHOD_ID);
if (ret == -EOPNOTSUPP)
dev_err(&wmi_priv.bios_attr_wdev->dev, "admin password must be configured\n");
else if (ret == -EACCES)
dev_err(&wmi_priv.bios_attr_wdev->dev, "invalid password\n");
out:
kfree(buffer);
mutex_unlock(&wmi_priv.mutex);
return ret;
}
/**
* set_bios_defaults() - Resets BIOS defaults
* @deftype: the type of BIOS value reset to issue.
*
* Resets BIOS defaults
*/
int set_bios_defaults(u8 deftype)
{
size_t security_area_size, buffer_size;
size_t integer_area_size = sizeof(u8);
char *buffer = NULL;
u8 *defaultType;
int ret;
mutex_lock(&wmi_priv.mutex);
if (!wmi_priv.bios_attr_wdev) {
ret = -ENODEV;
goto out;
}
security_area_size = calculate_security_buffer(wmi_priv.current_admin_password);
buffer_size = security_area_size + integer_area_size;
buffer = kzalloc(buffer_size, GFP_KERNEL);
if (!buffer) {
ret = -ENOMEM;
goto out;
}
/* build security area */
populate_security_buffer(buffer, wmi_priv.current_admin_password);
defaultType = buffer + security_area_size;
*defaultType = deftype;
ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev, buffer, buffer_size,
SETBIOSDEFAULTS_METHOD_ID);
if (ret)
dev_err(&wmi_priv.bios_attr_wdev->dev, "reset BIOS defaults failed: %d\n", ret);
kfree(buffer);
out:
mutex_unlock(&wmi_priv.mutex);
return ret;
}
static int bios_attr_set_interface_probe(struct wmi_device *wdev, const void *context)
{
mutex_lock(&wmi_priv.mutex);
wmi_priv.bios_attr_wdev = wdev;
mutex_unlock(&wmi_priv.mutex);
return 0;
}
static int bios_attr_set_interface_remove(struct wmi_device *wdev)
{
mutex_lock(&wmi_priv.mutex);
wmi_priv.bios_attr_wdev = NULL;
mutex_unlock(&wmi_priv.mutex);
return 0;
}
static const struct wmi_device_id bios_attr_set_interface_id_table[] = {
{ .guid_string = DELL_WMI_BIOS_ATTRIBUTES_INTERFACE_GUID },
{ },
};
static struct wmi_driver bios_attr_set_interface_driver = {
.driver = {
.name = DRIVER_NAME
},
.probe = bios_attr_set_interface_probe,
.remove = bios_attr_set_interface_remove,
.id_table = bios_attr_set_interface_id_table,
};
int init_bios_attr_set_interface(void)
{
return wmi_driver_register(&bios_attr_set_interface_driver);
}
void exit_bios_attr_set_interface(void)
{
wmi_driver_unregister(&bios_attr_set_interface_driver);
}
MODULE_DEVICE_TABLE(wmi, bios_attr_set_interface_id_table);
/* SPDX-License-Identifier: GPL-2.0
* Definitions for kernel modules using Dell WMI System Management Driver
*
* Copyright (c) 2020 Dell Inc.
*/
#ifndef _DELL_WMI_BIOS_ATTR_H_
#define _DELL_WMI_BIOS_ATTR_H_
#include <linux/wmi.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/capability.h>
#define DRIVER_NAME "dell-wmi-sysman"
#define MAX_BUFF 512
#define DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID "F1DDEE52-063C-4784-A11E-8A06684B9BF5"
#define DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID "F1DDEE52-063C-4784-A11E-8A06684B9BFA"
#define DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID "F1DDEE52-063C-4784-A11E-8A06684B9BF9"
#define DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID "0894B8D6-44A6-4719-97D7-6AD24108BFD4"
#define DELL_WMI_BIOS_ATTRIBUTES_INTERFACE_GUID "F1DDEE52-063C-4784-A11E-8A06684B9BF4"
#define DELL_WMI_BIOS_PASSWORD_INTERFACE_GUID "70FE8229-D03B-4214-A1C6-1F884B1A892A"
struct enumeration_data {
struct kobject *attr_name_kobj;
char display_name_language_code[MAX_BUFF];
char dell_value_modifier[MAX_BUFF];
char possible_values[MAX_BUFF];
char attribute_name[MAX_BUFF];
char default_value[MAX_BUFF];
char dell_modifier[MAX_BUFF];
char display_name[MAX_BUFF];
};
struct integer_data {
struct kobject *attr_name_kobj;
char display_name_language_code[MAX_BUFF];
char attribute_name[MAX_BUFF];
char dell_modifier[MAX_BUFF];
char display_name[MAX_BUFF];
int scalar_increment;
int default_value;
int min_value;
int max_value;
};
struct str_data {
struct kobject *attr_name_kobj;
char display_name_language_code[MAX_BUFF];
char attribute_name[MAX_BUFF];
char display_name[MAX_BUFF];
char default_value[MAX_BUFF];
char dell_modifier[MAX_BUFF];
int min_length;
int max_length;
};
struct po_data {
struct kobject *attr_name_kobj;
char attribute_name[MAX_BUFF];
int min_password_length;
int max_password_length;
};
struct wmi_sysman_priv {
char current_admin_password[MAX_BUFF];
char current_system_password[MAX_BUFF];
struct wmi_device *password_attr_wdev;
struct wmi_device *bios_attr_wdev;
struct kset *authentication_dir_kset;
struct kset *main_dir_kset;
struct device *class_dev;
struct enumeration_data *enumeration_data;
int enumeration_instances_count;
struct integer_data *integer_data;
int integer_instances_count;
struct str_data *str_data;
int str_instances_count;
struct po_data *po_data;
int po_instances_count;
bool pending_changes;
struct mutex mutex;
};
/* global structure used by multiple WMI interfaces */
extern struct wmi_sysman_priv wmi_priv;
enum { ENUM, INT, STR, PO };
enum {
ATTR_NAME,
DISPL_NAME_LANG_CODE,
DISPLAY_NAME,
DEFAULT_VAL,
CURRENT_VAL,
MODIFIER
};
#define get_instance_id(type) \
static int get_##type##_instance_id(struct kobject *kobj) \
{ \
int i; \
for (i = 0; i <= wmi_priv.type##_instances_count; i++) { \
if (!(strcmp(kobj->name, wmi_priv.type##_data[i].attribute_name)))\
return i; \
} \
return -EIO; \
}
#define attribute_s_property_show(name, type) \
static ssize_t name##_show(struct kobject *kobj, struct kobj_attribute *attr, \
char *buf) \
{ \
int i = get_##type##_instance_id(kobj); \
if (i >= 0) \
return sprintf(buf, "%s\n", wmi_priv.type##_data[i].name); \
return 0; \
}
#define attribute_n_property_show(name, type) \
static ssize_t name##_show(struct kobject *kobj, struct kobj_attribute *attr, \
char *buf) \
{ \
int i = get_##type##_instance_id(kobj); \
if (i >= 0) \
return sprintf(buf, "%d\n", wmi_priv.type##_data[i].name); \
return 0; \
}
#define attribute_property_store(curr_val, type) \
static ssize_t curr_val##_store(struct kobject *kobj, \
struct kobj_attribute *attr, \
const char *buf, size_t count) \
{ \
char *p, *buf_cp; \
int i, ret = -EIO; \
buf_cp = kstrdup(buf, GFP_KERNEL); \
if (!buf_cp) \
return -ENOMEM; \
p = memchr(buf_cp, '\n', count); \
\
if (p != NULL) \
*p = '\0'; \
i = get_##type##_instance_id(kobj); \
if (i >= 0) \
ret = validate_##type##_input(i, buf_cp); \
if (!ret) \
ret = set_attribute(kobj->name, buf_cp); \
kfree(buf_cp); \
return ret ? ret : count; \
}
union acpi_object *get_wmiobj_pointer(int instance_id, const char *guid_string);
int get_instance_count(const char *guid_string);
void strlcpy_attr(char *dest, char *src);
int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
struct kobject *attr_name_kobj);
int alloc_enum_data(void);
void exit_enum_attributes(void);
int populate_int_data(union acpi_object *integer_obj, int instance_id,
struct kobject *attr_name_kobj);
int alloc_int_data(void);
void exit_int_attributes(void);
int populate_str_data(union acpi_object *str_obj, int instance_id, struct kobject *attr_name_kobj);
int alloc_str_data(void);
void exit_str_attributes(void);
int populate_po_data(union acpi_object *po_obj, int instance_id, struct kobject *attr_name_kobj);
int alloc_po_data(void);
void exit_po_attributes(void);
int set_attribute(const char *a_name, const char *a_value);
int set_bios_defaults(u8 defType);
void exit_bios_attr_set_interface(void);
int init_bios_attr_set_interface(void);
int map_wmi_error(int error_code);
size_t calculate_string_buffer(const char *str);
size_t calculate_security_buffer(char *authentication);
void populate_security_buffer(char *buffer, char *authentication);
ssize_t populate_string_buffer(char *buffer, size_t buffer_len, const char *str);
int set_new_password(const char *password_type, const char *new);
int init_bios_attr_pass_interface(void);
void exit_bios_attr_pass_interface(void);
#endif
// SPDX-License-Identifier: GPL-2.0
/*
* Functions corresponding to enumeration type attributes under
* BIOS Enumeration GUID for use with dell-wmi-sysman
*
* Copyright (c) 2020 Dell Inc.
*/
#include "dell-wmi-sysman.h"
get_instance_id(enumeration);
static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
int instance_id = get_enumeration_instance_id(kobj);
union acpi_object *obj;
ssize_t ret;
if (instance_id < 0)
return instance_id;
/* need to use specific instance_id and guid combination to get right data */
obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
if (!obj)
return -EIO;
if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING) {
kfree(obj);
return -EINVAL;
}
ret = snprintf(buf, PAGE_SIZE, "%s\n", obj->package.elements[CURRENT_VAL].string.pointer);
kfree(obj);
return ret;
}
/**
* validate_enumeration_input() - Validate input of current_value against possible values
* @instance_id: The instance on which input is validated
* @buf: Input value
*/
static int validate_enumeration_input(int instance_id, const char *buf)
{
char *options, *tmp, *p;
int ret = -EINVAL;
options = tmp = kstrdup(wmi_priv.enumeration_data[instance_id].possible_values,
GFP_KERNEL);
if (!options)
return -ENOMEM;
while ((p = strsep(&options, ";")) != NULL) {
if (!*p)
continue;
if (!strcasecmp(p, buf)) {
ret = 0;
break;
}
}
kfree(tmp);
return ret;
}
attribute_s_property_show(display_name_language_code, enumeration);
static struct kobj_attribute displ_langcode =
__ATTR_RO(display_name_language_code);
attribute_s_property_show(display_name, enumeration);
static struct kobj_attribute displ_name =
__ATTR_RO(display_name);
attribute_s_property_show(default_value, enumeration);
static struct kobj_attribute default_val =
__ATTR_RO(default_value);
attribute_property_store(current_value, enumeration);
static struct kobj_attribute current_val =
__ATTR_RW_MODE(current_value, 0600);
attribute_s_property_show(dell_modifier, enumeration);
static struct kobj_attribute modifier =
__ATTR_RO(dell_modifier);
attribute_s_property_show(dell_value_modifier, enumeration);
static struct kobj_attribute value_modfr =
__ATTR_RO(dell_value_modifier);
attribute_s_property_show(possible_values, enumeration);
static struct kobj_attribute poss_val =
__ATTR_RO(possible_values);
static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
return sprintf(buf, "enumeration\n");
}
static struct kobj_attribute type =
__ATTR_RO(type);
static struct attribute *enumeration_attrs[] = {
&displ_langcode.attr,
&displ_name.attr,
&default_val.attr,
&current_val.attr,
&modifier.attr,
&value_modfr.attr,
&poss_val.attr,
&type.attr,
NULL,
};
static const struct attribute_group enumeration_attr_group = {
.attrs = enumeration_attrs,
};
int alloc_enum_data(void)
{
int ret = 0;
wmi_priv.enumeration_instances_count =
get_instance_count(DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
wmi_priv.enumeration_data = kcalloc(wmi_priv.enumeration_instances_count,
sizeof(struct enumeration_data), GFP_KERNEL);
if (!wmi_priv.enumeration_data) {
wmi_priv.enumeration_instances_count = 0;
ret = -ENOMEM;
}
return ret;
}
/**
* populate_enum_data() - Populate all properties of an instance under enumeration attribute
* @enumeration_obj: ACPI object with enumeration data
* @instance_id: The instance to enumerate
* @attr_name_kobj: The parent kernel object
*/
int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
struct kobject *attr_name_kobj)
{
int i, next_obj, value_modifier_count, possible_values_count;
wmi_priv.enumeration_data[instance_id].attr_name_kobj = attr_name_kobj;
strlcpy_attr(wmi_priv.enumeration_data[instance_id].attribute_name,
enumeration_obj[ATTR_NAME].string.pointer);
strlcpy_attr(wmi_priv.enumeration_data[instance_id].display_name_language_code,
enumeration_obj[DISPL_NAME_LANG_CODE].string.pointer);
strlcpy_attr(wmi_priv.enumeration_data[instance_id].display_name,
enumeration_obj[DISPLAY_NAME].string.pointer);
strlcpy_attr(wmi_priv.enumeration_data[instance_id].default_value,
enumeration_obj[DEFAULT_VAL].string.pointer);
strlcpy_attr(wmi_priv.enumeration_data[instance_id].dell_modifier,
enumeration_obj[MODIFIER].string.pointer);
next_obj = MODIFIER + 1;
value_modifier_count = (uintptr_t)enumeration_obj[next_obj].string.pointer;
for (i = 0; i < value_modifier_count; i++) {
strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier,
enumeration_obj[++next_obj].string.pointer);
strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ";");
}
possible_values_count = (uintptr_t) enumeration_obj[++next_obj].string.pointer;
for (i = 0; i < possible_values_count; i++) {
strcat(wmi_priv.enumeration_data[instance_id].possible_values,
enumeration_obj[++next_obj].string.pointer);
strcat(wmi_priv.enumeration_data[instance_id].possible_values, ";");
}
return sysfs_create_group(attr_name_kobj, &enumeration_attr_group);
}
/**
* exit_enum_attributes() - Clear all attribute data
*
* Clears all data allocated for this group of attributes
*/
void exit_enum_attributes(void)
{
int instance_id;
for (instance_id = 0; instance_id < wmi_priv.enumeration_instances_count; instance_id++) {
if (wmi_priv.enumeration_data[instance_id].attr_name_kobj)
sysfs_remove_group(wmi_priv.enumeration_data[instance_id].attr_name_kobj,
&enumeration_attr_group);
}
kfree(wmi_priv.enumeration_data);
}
// SPDX-License-Identifier: GPL-2.0
/*
* Functions corresponding to integer type attributes under BIOS Integer GUID for use with
* dell-wmi-sysman
*
* Copyright (c) 2020 Dell Inc.
*/
#include "dell-wmi-sysman.h"
enum int_properties {MIN_VALUE = 6, MAX_VALUE, SCALAR_INCR};
get_instance_id(integer);
static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
int instance_id = get_integer_instance_id(kobj);
union acpi_object *obj;
ssize_t ret;
if (instance_id < 0)
return instance_id;
/* need to use specific instance_id and guid combination to get right data */
obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
if (!obj)
return -EIO;
if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_INTEGER) {
kfree(obj);
return -EINVAL;
}
ret = snprintf(buf, PAGE_SIZE, "%lld\n", obj->package.elements[CURRENT_VAL].integer.value);
kfree(obj);
return ret;
}
/**
* validate_integer_input() - Validate input of current_value against lower and upper bound
* @instance_id: The instance on which input is validated
* @buf: Input value
*/
static int validate_integer_input(int instance_id, char *buf)
{
int in_val;
int ret;
ret = kstrtoint(buf, 0, &in_val);
if (ret)
return ret;
if (in_val < wmi_priv.integer_data[instance_id].min_value ||
in_val > wmi_priv.integer_data[instance_id].max_value)
return -EINVAL;
/* workaround for BIOS error.
* validate input to avoid setting 0 when integer input passed with + sign
*/
if (*buf == '+')
memmove(buf, (buf + 1), strlen(buf + 1) + 1);
return ret;
}
attribute_s_property_show(display_name_language_code, integer);
static struct kobj_attribute integer_displ_langcode =
__ATTR_RO(display_name_language_code);
attribute_s_property_show(display_name, integer);
static struct kobj_attribute integer_displ_name =
__ATTR_RO(display_name);
attribute_n_property_show(default_value, integer);
static struct kobj_attribute integer_default_val =
__ATTR_RO(default_value);
attribute_property_store(current_value, integer);
static struct kobj_attribute integer_current_val =
__ATTR_RW_MODE(current_value, 0600);
attribute_s_property_show(dell_modifier, integer);
static struct kobj_attribute integer_modifier =
__ATTR_RO(dell_modifier);
attribute_n_property_show(min_value, integer);
static struct kobj_attribute integer_lower_bound =
__ATTR_RO(min_value);
attribute_n_property_show(max_value, integer);
static struct kobj_attribute integer_upper_bound =
__ATTR_RO(max_value);
attribute_n_property_show(scalar_increment, integer);
static struct kobj_attribute integer_scalar_increment =
__ATTR_RO(scalar_increment);
static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
return sprintf(buf, "integer\n");
}
static struct kobj_attribute integer_type =
__ATTR_RO(type);
static struct attribute *integer_attrs[] = {
&integer_displ_langcode.attr,
&integer_displ_name.attr,
&integer_default_val.attr,
&integer_current_val.attr,
&integer_modifier.attr,
&integer_lower_bound.attr,
&integer_upper_bound.attr,
&integer_scalar_increment.attr,
&integer_type.attr,
NULL,
};
static const struct attribute_group integer_attr_group = {
.attrs = integer_attrs,
};
int alloc_int_data(void)
{
int ret = 0;
wmi_priv.integer_instances_count = get_instance_count(DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
wmi_priv.integer_data = kcalloc(wmi_priv.integer_instances_count,
sizeof(struct integer_data), GFP_KERNEL);
if (!wmi_priv.integer_data) {
wmi_priv.integer_instances_count = 0;
ret = -ENOMEM;
}
return ret;
}
/**
* populate_int_data() - Populate all properties of an instance under integer attribute
* @integer_obj: ACPI object with integer data
* @instance_id: The instance to enumerate
* @attr_name_kobj: The parent kernel object
*/
int populate_int_data(union acpi_object *integer_obj, int instance_id,
struct kobject *attr_name_kobj)
{
wmi_priv.integer_data[instance_id].attr_name_kobj = attr_name_kobj;
strlcpy_attr(wmi_priv.integer_data[instance_id].attribute_name,
integer_obj[ATTR_NAME].string.pointer);
strlcpy_attr(wmi_priv.integer_data[instance_id].display_name_language_code,
integer_obj[DISPL_NAME_LANG_CODE].string.pointer);
strlcpy_attr(wmi_priv.integer_data[instance_id].display_name,
integer_obj[DISPLAY_NAME].string.pointer);
wmi_priv.integer_data[instance_id].default_value =
(uintptr_t)integer_obj[DEFAULT_VAL].string.pointer;
strlcpy_attr(wmi_priv.integer_data[instance_id].dell_modifier,
integer_obj[MODIFIER].string.pointer);
wmi_priv.integer_data[instance_id].min_value =
(uintptr_t)integer_obj[MIN_VALUE].string.pointer;
wmi_priv.integer_data[instance_id].max_value =
(uintptr_t)integer_obj[MAX_VALUE].string.pointer;
wmi_priv.integer_data[instance_id].scalar_increment =
(uintptr_t)integer_obj[SCALAR_INCR].string.pointer;
return sysfs_create_group(attr_name_kobj, &integer_attr_group);
}
/**
* exit_int_attributes() - Clear all attribute data
*
* Clears all data allocated for this group of attributes
*/
void exit_int_attributes(void)
{
int instance_id;
for (instance_id = 0; instance_id < wmi_priv.integer_instances_count; instance_id++) {
if (wmi_priv.integer_data[instance_id].attr_name_kobj)
sysfs_remove_group(wmi_priv.integer_data[instance_id].attr_name_kobj,
&integer_attr_group);
}
kfree(wmi_priv.integer_data);
}
// SPDX-License-Identifier: GPL-2.0
/*
* Functions corresponding to password object type attributes under BIOS Password Object GUID for
* use with dell-wmi-sysman
*
* Copyright (c) 2020 Dell Inc.
*/
#include "dell-wmi-sysman.h"
enum po_properties {IS_PASS_SET = 1, MIN_PASS_LEN, MAX_PASS_LEN};
get_instance_id(po);
static ssize_t is_enabled_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
int instance_id = get_po_instance_id(kobj);
union acpi_object *obj;
ssize_t ret;
if (instance_id < 0)
return instance_id;
/* need to use specific instance_id and guid combination to get right data */
obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
if (!obj)
return -EIO;
if (obj->package.elements[IS_PASS_SET].type != ACPI_TYPE_INTEGER) {
kfree(obj);
return -EINVAL;
}
ret = snprintf(buf, PAGE_SIZE, "%lld\n", obj->package.elements[IS_PASS_SET].integer.value);
kfree(obj);
return ret;
}
static struct kobj_attribute po_is_pass_set = __ATTR_RO(is_enabled);
static ssize_t current_password_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
{
char *target = NULL;
int length;
length = strlen(buf);
if (buf[length-1] == '\n')
length--;
/* firmware does verifiation of min/max password length,
* hence only check for not exceeding MAX_BUFF here.
*/
if (length >= MAX_BUFF)
return -EINVAL;
if (strcmp(kobj->name, "Admin") == 0)
target = wmi_priv.current_admin_password;
else if (strcmp(kobj->name, "System") == 0)
target = wmi_priv.current_system_password;
if (!target)
return -EIO;
memcpy(target, buf, length);
target[length] = '\0';
return count;
}
static struct kobj_attribute po_current_password = __ATTR_WO(current_password);
static ssize_t new_password_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
{
char *p, *buf_cp;
int ret;
buf_cp = kstrdup(buf, GFP_KERNEL);
if (!buf_cp)
return -ENOMEM;
p = memchr(buf_cp, '\n', count);
if (p != NULL)
*p = '\0';
if (strlen(buf_cp) > MAX_BUFF) {
ret = -EINVAL;
goto out;
}
ret = set_new_password(kobj->name, buf_cp);
out:
kfree(buf_cp);
return ret ? ret : count;
}
static struct kobj_attribute po_new_password = __ATTR_WO(new_password);
attribute_n_property_show(min_password_length, po);
static struct kobj_attribute po_min_pass_length = __ATTR_RO(min_password_length);
attribute_n_property_show(max_password_length, po);
static struct kobj_attribute po_max_pass_length = __ATTR_RO(max_password_length);
static ssize_t mechanism_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
return sprintf(buf, "password\n");
}
static struct kobj_attribute po_mechanism = __ATTR_RO(mechanism);
static ssize_t role_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
if (strcmp(kobj->name, "Admin") == 0)
return sprintf(buf, "bios-admin\n");
else if (strcmp(kobj->name, "System") == 0)
return sprintf(buf, "power-on\n");
return -EIO;
}
static struct kobj_attribute po_role = __ATTR_RO(role);
static struct attribute *po_attrs[] = {
&po_is_pass_set.attr,
&po_min_pass_length.attr,
&po_max_pass_length.attr,
&po_current_password.attr,
&po_new_password.attr,
&po_role.attr,
&po_mechanism.attr,
NULL,
};
static const struct attribute_group po_attr_group = {
.attrs = po_attrs,
};
int alloc_po_data(void)
{
int ret = 0;
wmi_priv.po_instances_count = get_instance_count(DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
wmi_priv.po_data = kcalloc(wmi_priv.po_instances_count, sizeof(struct po_data), GFP_KERNEL);
if (!wmi_priv.po_data) {
wmi_priv.po_instances_count = 0;
ret = -ENOMEM;
}
return ret;
}
/**
* populate_po_data() - Populate all properties of an instance under password object attribute
* @po_obj: ACPI object with password object data
* @instance_id: The instance to enumerate
* @attr_name_kobj: The parent kernel object
*/
int populate_po_data(union acpi_object *po_obj, int instance_id, struct kobject *attr_name_kobj)
{
wmi_priv.po_data[instance_id].attr_name_kobj = attr_name_kobj;
strlcpy_attr(wmi_priv.po_data[instance_id].attribute_name,
po_obj[ATTR_NAME].string.pointer);
wmi_priv.po_data[instance_id].min_password_length =
(uintptr_t)po_obj[MIN_PASS_LEN].string.pointer;
wmi_priv.po_data[instance_id].max_password_length =
(uintptr_t) po_obj[MAX_PASS_LEN].string.pointer;
return sysfs_create_group(attr_name_kobj, &po_attr_group);
}
/**
* exit_po_attributes() - Clear all attribute data
*
* Clears all data allocated for this group of attributes
*/
void exit_po_attributes(void)
{
int instance_id;
for (instance_id = 0; instance_id < wmi_priv.po_instances_count; instance_id++) {
if (wmi_priv.po_data[instance_id].attr_name_kobj)
sysfs_remove_group(wmi_priv.po_data[instance_id].attr_name_kobj,
&po_attr_group);
}
kfree(wmi_priv.po_data);
}
// SPDX-License-Identifier: GPL-2.0
/*
* Functions corresponding to SET password methods under BIOS attributes interface GUID
*
* Copyright (c) 2020 Dell Inc.
*/
#include <linux/wmi.h>
#include "dell-wmi-sysman.h"
static int call_password_interface(struct wmi_device *wdev, char *in_args, size_t size)
{
struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
struct acpi_buffer input;
union acpi_object *obj;
acpi_status status;
int ret = -EIO;
input.length = (acpi_size) size;
input.pointer = in_args;
status = wmidev_evaluate_method(wdev, 0, 1, &input, &output);
if (ACPI_FAILURE(status))
return -EIO;
obj = (union acpi_object *)output.pointer;
if (obj->type == ACPI_TYPE_INTEGER)
ret = obj->integer.value;
kfree(output.pointer);
/* let userland know it may need to check is_password_set again */
kobject_uevent(&wmi_priv.class_dev->kobj, KOBJ_CHANGE);
return map_wmi_error(ret);
}
/**
* set_new_password() - Sets a system admin password
* @password_type: The type of password to set
* @new: The new password
*
* Sets the password using plaintext interface
*/
int set_new_password(const char *password_type, const char *new)
{
size_t password_type_size, current_password_size, new_size;
size_t security_area_size, buffer_size;
char *buffer = NULL, *start;
char *current_password;
int ret;
mutex_lock(&wmi_priv.mutex);
if (!wmi_priv.password_attr_wdev) {
ret = -ENODEV;
goto out;
}
if (strcmp(password_type, "Admin") == 0) {
current_password = wmi_priv.current_admin_password;
} else if (strcmp(password_type, "System") == 0) {
current_password = wmi_priv.current_system_password;
} else {
ret = -EINVAL;
dev_err(&wmi_priv.password_attr_wdev->dev, "unknown password type %s\n",
password_type);
goto out;
}
/* build/calculate buffer */
security_area_size = calculate_security_buffer(wmi_priv.current_admin_password);
password_type_size = calculate_string_buffer(password_type);
current_password_size = calculate_string_buffer(current_password);
new_size = calculate_string_buffer(new);
buffer_size = security_area_size + password_type_size + current_password_size + new_size;
buffer = kzalloc(buffer_size, GFP_KERNEL);
if (!buffer) {
ret = -ENOMEM;
goto out;
}
/* build security area */
populate_security_buffer(buffer, wmi_priv.current_admin_password);
/* build variables to set */
start = buffer + security_area_size;
ret = populate_string_buffer(start, password_type_size, password_type);
if (ret < 0)
goto out;
start += ret;
ret = populate_string_buffer(start, current_password_size, current_password);
if (ret < 0)
goto out;
start += ret;
ret = populate_string_buffer(start, new_size, new);
if (ret < 0)
goto out;
print_hex_dump_bytes("set new password data: ", DUMP_PREFIX_NONE, buffer, buffer_size);
ret = call_password_interface(wmi_priv.password_attr_wdev, buffer, buffer_size);
/* clear current_password here and use user input from wmi_priv.current_password */
if (!ret)
memset(current_password, 0, MAX_BUFF);
/* explain to user the detailed failure reason */
else if (ret == -EOPNOTSUPP)
dev_err(&wmi_priv.password_attr_wdev->dev, "admin password must be configured\n");
else if (ret == -EACCES)
dev_err(&wmi_priv.password_attr_wdev->dev, "invalid password\n");
out:
kfree(buffer);
mutex_unlock(&wmi_priv.mutex);
return ret;
}
static int bios_attr_pass_interface_probe(struct wmi_device *wdev, const void *context)
{
mutex_lock(&wmi_priv.mutex);
wmi_priv.password_attr_wdev = wdev;
mutex_unlock(&wmi_priv.mutex);
return 0;
}
static int bios_attr_pass_interface_remove(struct wmi_device *wdev)
{
mutex_lock(&wmi_priv.mutex);
wmi_priv.password_attr_wdev = NULL;
mutex_unlock(&wmi_priv.mutex);
return 0;
}
static const struct wmi_device_id bios_attr_pass_interface_id_table[] = {
{ .guid_string = DELL_WMI_BIOS_PASSWORD_INTERFACE_GUID },
{ },
};
static struct wmi_driver bios_attr_pass_interface_driver = {
.driver = {
.name = DRIVER_NAME"-password"
},
.probe = bios_attr_pass_interface_probe,
.remove = bios_attr_pass_interface_remove,
.id_table = bios_attr_pass_interface_id_table,
};
int init_bios_attr_pass_interface(void)
{
return wmi_driver_register(&bios_attr_pass_interface_driver);
}
void exit_bios_attr_pass_interface(void)
{
wmi_driver_unregister(&bios_attr_pass_interface_driver);
}
MODULE_DEVICE_TABLE(wmi, bios_attr_pass_interface_id_table);
// SPDX-License-Identifier: GPL-2.0
/*
* Functions corresponding to string type attributes under BIOS String GUID for use with
* dell-wmi-sysman
*
* Copyright (c) 2020 Dell Inc.
*/
#include "dell-wmi-sysman.h"
enum string_properties {MIN_LEN = 6, MAX_LEN};
get_instance_id(str);
static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
int instance_id = get_str_instance_id(kobj);
union acpi_object *obj;
ssize_t ret;
if (instance_id < 0)
return -EIO;
/* need to use specific instance_id and guid combination to get right data */
obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
if (!obj)
return -EIO;
if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING) {
kfree(obj);
return -EINVAL;
}
ret = snprintf(buf, PAGE_SIZE, "%s\n", obj->package.elements[CURRENT_VAL].string.pointer);
kfree(obj);
return ret;
}
/**
* validate_str_input() - Validate input of current_value against min and max lengths
* @instance_id: The instance on which input is validated
* @buf: Input value
*/
static int validate_str_input(int instance_id, const char *buf)
{
int in_len = strlen(buf);
if ((in_len < wmi_priv.str_data[instance_id].min_length) ||
(in_len > wmi_priv.str_data[instance_id].max_length))
return -EINVAL;
return 0;
}
attribute_s_property_show(display_name_language_code, str);
static struct kobj_attribute str_displ_langcode =
__ATTR_RO(display_name_language_code);
attribute_s_property_show(display_name, str);
static struct kobj_attribute str_displ_name =
__ATTR_RO(display_name);
attribute_s_property_show(default_value, str);
static struct kobj_attribute str_default_val =
__ATTR_RO(default_value);
attribute_property_store(current_value, str);
static struct kobj_attribute str_current_val =
__ATTR_RW_MODE(current_value, 0600);
attribute_s_property_show(dell_modifier, str);
static struct kobj_attribute str_modifier =
__ATTR_RO(dell_modifier);
attribute_n_property_show(min_length, str);
static struct kobj_attribute str_min_length =
__ATTR_RO(min_length);
attribute_n_property_show(max_length, str);
static struct kobj_attribute str_max_length =
__ATTR_RO(max_length);
static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
return sprintf(buf, "string\n");
}
static struct kobj_attribute str_type =
__ATTR_RO(type);
static struct attribute *str_attrs[] = {
&str_displ_langcode.attr,
&str_displ_name.attr,
&str_default_val.attr,
&str_current_val.attr,
&str_modifier.attr,
&str_min_length.attr,
&str_max_length.attr,
&str_type.attr,
NULL,
};
static const struct attribute_group str_attr_group = {
.attrs = str_attrs,
};
int alloc_str_data(void)
{
int ret = 0;
wmi_priv.str_instances_count = get_instance_count(DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
wmi_priv.str_data = kcalloc(wmi_priv.str_instances_count,
sizeof(struct str_data), GFP_KERNEL);
if (!wmi_priv.str_data) {
wmi_priv.str_instances_count = 0;
ret = -ENOMEM;
}
return ret;
}
/**
* populate_str_data() - Populate all properties of an instance under string attribute
* @str_obj: ACPI object with integer data
* @instance_id: The instance to enumerate
* @attr_name_kobj: The parent kernel object
*/
int populate_str_data(union acpi_object *str_obj, int instance_id, struct kobject *attr_name_kobj)
{
wmi_priv.str_data[instance_id].attr_name_kobj = attr_name_kobj;
strlcpy_attr(wmi_priv.str_data[instance_id].attribute_name,
str_obj[ATTR_NAME].string.pointer);
strlcpy_attr(wmi_priv.str_data[instance_id].display_name_language_code,
str_obj[DISPL_NAME_LANG_CODE].string.pointer);
strlcpy_attr(wmi_priv.str_data[instance_id].display_name,
str_obj[DISPLAY_NAME].string.pointer);
strlcpy_attr(wmi_priv.str_data[instance_id].default_value,
str_obj[DEFAULT_VAL].string.pointer);
strlcpy_attr(wmi_priv.str_data[instance_id].dell_modifier,
str_obj[MODIFIER].string.pointer);
wmi_priv.str_data[instance_id].min_length = (uintptr_t)str_obj[MIN_LEN].string.pointer;
wmi_priv.str_data[instance_id].max_length = (uintptr_t) str_obj[MAX_LEN].string.pointer;
return sysfs_create_group(attr_name_kobj, &str_attr_group);
}
/**
* exit_str_attributes() - Clear all attribute data
*
* Clears all data allocated for this group of attributes
*/
void exit_str_attributes(void)
{
int instance_id;
for (instance_id = 0; instance_id < wmi_priv.str_instances_count; instance_id++) {
if (wmi_priv.str_data[instance_id].attr_name_kobj)
sysfs_remove_group(wmi_priv.str_data[instance_id].attr_name_kobj,
&str_attr_group);
}
kfree(wmi_priv.str_data);
}
This diff is collapsed.
......@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/types.h>
#define IRQ_RESOURCE_TYPE GENMASK(1, 0)
......@@ -59,7 +60,6 @@ static int i2c_multi_inst_count_resources(struct acpi_device *adev)
static int i2c_multi_inst_probe(struct platform_device *pdev)
{
struct i2c_multi_inst_data *multi;
const struct acpi_device_id *match;
const struct i2c_inst_data *inst_data;
struct i2c_board_info board_info = {};
struct device *dev = &pdev->dev;
......@@ -67,12 +67,11 @@ static int i2c_multi_inst_probe(struct platform_device *pdev)
char name[32];
int i, ret;
match = acpi_match_device(dev->driver->acpi_match_table, dev);
if (!match) {
inst_data = device_get_match_data(dev);
if (!inst_data) {
dev_err(dev, "Error ACPI match data is missing\n");
return -ENODEV;
}
inst_data = (const struct i2c_inst_data *)match->driver_data;
adev = ACPI_COMPANION(dev);
......@@ -118,9 +117,8 @@ static int i2c_multi_inst_probe(struct platform_device *pdev)
}
multi->clients[i] = i2c_acpi_new_device(dev, i, &board_info);
if (IS_ERR(multi->clients[i])) {
ret = PTR_ERR(multi->clients[i]);
if (ret != -EPROBE_DEFER)
dev_err(dev, "Error creating i2c-client, idx %d\n", i);
ret = dev_err_probe(dev, PTR_ERR(multi->clients[i]),
"Error creating i2c-client, idx %d\n", i);
goto error;
}
}
......@@ -189,7 +187,7 @@ MODULE_DEVICE_TABLE(acpi, i2c_multi_inst_acpi_ids);
static struct platform_driver i2c_multi_inst_driver = {
.driver = {
.name = "I2C multi instantiate pseudo device driver",
.acpi_match_table = ACPI_PTR(i2c_multi_inst_acpi_ids),
.acpi_match_table = i2c_multi_inst_acpi_ids,
},
.probe = i2c_multi_inst_probe,
.remove = i2c_multi_inst_remove,
......
This diff is collapsed.
......@@ -15,9 +15,13 @@
#include <linux/platform_device.h>
#include <linux/suspend.h>
/* Returned when NOT in tablet mode on some HP Stream x360 11 models */
#define VGBS_TABLET_MODE_FLAG_ALT 0x10
/* When NOT in tablet mode, VGBS returns with the flag 0x40 */
#define TABLET_MODE_FLAG 0x40
#define DOCK_MODE_FLAG 0x80
#define VGBS_TABLET_MODE_FLAG 0x40
#define VGBS_DOCK_MODE_FLAG 0x80
#define VGBS_TABLET_MODE_FLAGS (VGBS_TABLET_MODE_FLAG | VGBS_TABLET_MODE_FLAG_ALT)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("AceLan Kao");
......@@ -72,9 +76,9 @@ static void detect_tablet_mode(struct platform_device *device)
if (ACPI_FAILURE(status))
return;
m = !(vgbs & TABLET_MODE_FLAG);
m = !(vgbs & VGBS_TABLET_MODE_FLAGS);
input_report_switch(priv->input_dev, SW_TABLET_MODE, m);
m = (vgbs & DOCK_MODE_FLAG) ? 1 : 0;
m = (vgbs & VGBS_DOCK_MODE_FLAG) ? 1 : 0;
input_report_switch(priv->input_dev, SW_DOCK, m);
}
......@@ -212,6 +216,12 @@ static const struct dmi_system_id dmi_switches_allow_list[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion 13 x360 PC"),
},
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Switch SA5-271"),
},
},
{} /* Array terminator */
};
......
......@@ -929,7 +929,7 @@ static void pmc_core_slps0_dbg_latch(struct pmc_dev *pmcdev, bool reset)
fd |= CNP_PMC_LATCH_SLPS0_EVENTS;
pmc_core_reg_write(pmcdev, map->slps0_dbg_offset, fd);
slps0_dbg_latch = 0;
slps0_dbg_latch = false;
out_unlock:
mutex_unlock(&pmcdev->lock);
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _INTEL_PMT_CLASS_H
#define _INTEL_PMT_CLASS_H
#include <linux/platform_device.h>
#include <linux/xarray.h>
#include <linux/types.h>
#include <linux/bits.h>
#include <linux/err.h>
#include <linux/io.h>
/* PMT access types */
#define ACCESS_BARID 2
#define ACCESS_LOCAL 3
/* PMT discovery base address/offset register layout */
#define GET_BIR(v) ((v) & GENMASK(2, 0))
#define GET_ADDRESS(v) ((v) & GENMASK(31, 3))
struct intel_pmt_entry {
struct bin_attribute pmt_bin_attr;
struct kobject *kobj;
void __iomem *disc_table;
void __iomem *base;
unsigned long base_addr;
size_t size;
u32 guid;
int devid;
};
struct intel_pmt_header {
u32 base_offset;
u32 size;
u32 guid;
u8 access_type;
};
struct intel_pmt_namespace {
const char *name;
struct xarray *xa;
const struct attribute_group *attr_grp;
int (*pmt_header_decode)(struct intel_pmt_entry *entry,
struct intel_pmt_header *header,
struct device *dev);
};
int intel_pmt_dev_create(struct intel_pmt_entry *entry,
struct intel_pmt_namespace *ns,
struct platform_device *pdev, int idx);
void intel_pmt_dev_destroy(struct intel_pmt_entry *entry,
struct intel_pmt_namespace *ns);
#endif
This diff is collapsed.
This diff is collapsed.
......@@ -10,11 +10,11 @@
#ifndef __ISST_IF_COMMON_H
#define __ISST_IF_COMMON_H
#define INTEL_RAPL_PRIO_DEVID_0 0x3451
#define INTEL_CFG_MBOX_DEVID_0 0x3459
#define PCI_DEVICE_ID_INTEL_RAPL_PRIO_DEVID_0 0x3451
#define PCI_DEVICE_ID_INTEL_CFG_MBOX_DEVID_0 0x3459
#define INTEL_RAPL_PRIO_DEVID_1 0x3251
#define INTEL_CFG_MBOX_DEVID_1 0x3259
#define PCI_DEVICE_ID_INTEL_RAPL_PRIO_DEVID_1 0x3251
#define PCI_DEVICE_ID_INTEL_CFG_MBOX_DEVID_1 0x3259
/*
* Validate maximum commands in a single request.
......
......@@ -146,8 +146,8 @@ static long isst_if_mbox_proc_cmd(u8 *cmd_ptr, int *write_only, int resume)
}
static const struct pci_device_id isst_if_mbox_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, INTEL_CFG_MBOX_DEVID_0)},
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, INTEL_CFG_MBOX_DEVID_1)},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CFG_MBOX_DEVID_0)},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CFG_MBOX_DEVID_1)},
{ 0 },
};
MODULE_DEVICE_TABLE(pci, isst_if_mbox_ids);
......
This diff is collapsed.
This diff is collapsed.
......@@ -2467,13 +2467,11 @@ static int __sony_nc_gfx_switch_status_get(void)
* 0: integrated GFX (stamina)
*/
return result & 0x1 ? SPEED : STAMINA;
break;
case 0x015B:
/* 0: discrete GFX (speed)
* 1: integrated GFX (stamina)
*/
return result & 0x1 ? STAMINA : SPEED;
break;
case 0x0128:
/* it's a more elaborated bitmask, for now:
* 2: integrated GFX (stamina)
......@@ -2482,7 +2480,6 @@ static int __sony_nc_gfx_switch_status_get(void)
dprintk("GFX Status: 0x%x\n", result);
return result & 0x80 ? AUTO :
result & 0x02 ? STAMINA : SPEED;
break;
}
return -EINVAL;
}
......
This diff is collapsed.
......@@ -1260,13 +1260,10 @@ acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
switch (result) {
case -EINVAL:
return AE_BAD_PARAMETER;
break;
case -ENODEV:
return AE_NOT_FOUND;
break;
case -ETIME:
return AE_TIME;
break;
default:
return AE_OK;
}
......@@ -1347,7 +1344,7 @@ static int acpi_wmi_remove(struct platform_device *device)
acpi_remove_address_space_handler(acpi_device->handle,
ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
wmi_free_devices(acpi_device);
device_destroy(&wmi_bus_class, MKDEV(0, 0));
device_unregister((struct device *)dev_get_drvdata(&device->dev));
return 0;
}
......@@ -1401,7 +1398,7 @@ static int acpi_wmi_probe(struct platform_device *device)
return 0;
err_remove_busdev:
device_destroy(&wmi_bus_class, MKDEV(0, 0));
device_unregister(wmi_bus_dev);
err_remove_notify_handler:
acpi_remove_notify_handler(acpi_device->handle, ACPI_DEVICE_NOTIFY,
......
......@@ -62,6 +62,7 @@
/* Misc */
#define ASUS_WMI_DEVID_CAMERA 0x00060013
#define ASUS_WMI_DEVID_LID_FLIP 0x00060062
/* Storage */
#define ASUS_WMI_DEVID_CARDREADER 0x00080013
......
This diff is collapsed.
......@@ -804,7 +804,7 @@ int isst_get_process_ctdp(int cpu, int tdp_level, struct isst_pkg_ctdp *pkg_dev)
return ret;
}
if (!pkg_dev->enabled) {
if (!pkg_dev->enabled && is_skx_based_platform()) {
int freq;
freq = get_cpufreq_base_freq(cpu);
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment