Commit a0a4df6a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'platform-drivers-x86-v5.12-2' of...

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

Pull x86 platform drivers fixes from Hans de Goede:
 "A set of bug-fixes and some model specific quirks.

  Summary:

   - dell-wmi-sysman: A set of probe-error-exit-handling fixes to fix
     some systems which advertise the WMI GUIDs, but are not compatible,
     not booting

   - intel-vbtn/intel-hid: Misc. bugfixes

   - intel_pmc: Bug-fixes + a quirk to lower suspend power-consumption
     on Tiger Lake

   - thinkpad_acpi: misc bugfixes"

* tag 'platform-drivers-x86-v5.12-2' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86:
  platform/x86: intel_pmc_core: Ignore GBE LTR on Tiger Lake platforms
  platform/x86: intel_pmc_core: Update Kconfig
  platform/x86: intel_pmt_crashlog: Fix incorrect macros
  platform/x86: intel_pmt_class: Initial resource to 0
  platform/x86: intel-vbtn: Stop reporting SW_DOCK events
  platform/x86: dell-wmi-sysman: Cleanup create_attributes_level_sysfs_files()
  platform/x86: dell-wmi-sysman: Make sysman_init() return -ENODEV of the interfaces are not found
  platform/x86: dell-wmi-sysman: Cleanup sysman_init() error-exit handling
  platform/x86: dell-wmi-sysman: Fix release_attributes_data() getting called twice on init_bios_attributes() failure
  platform/x86: dell-wmi-sysman: Make it safe to call exit_foo_attributes() multiple times
  platform/x86: dell-wmi-sysman: Fix possible NULL pointer deref on exit
  platform/x86: dell-wmi-sysman: Fix crash caused by calling kset_unregister twice
  platform/x86: thinkpad_acpi: Disable DYTC CQL mode around switching to balanced mode
  platform/x86: thinkpad_acpi: Allow the FnLock LED to change state
  platform/x86: thinkpad_acpi: check dytc version for lapmode sysfs
  platform/x86: intel-hid: Support Lenovo ThinkPad X1 Tablet Gen 2
parents 8a9d2e13 d1635448
......@@ -1173,15 +1173,20 @@ config INTEL_PMC_CORE
depends on PCI
help
The Intel Platform Controller Hub for Intel Core SoCs provides access
to Power Management Controller registers via a PCI interface. This
to Power Management Controller registers via various interfaces. This
driver can utilize debugging capabilities and supported features as
exposed by the Power Management Controller.
exposed by the Power Management Controller. It also may perform some
tasks in the PMC in order to enable transition into the SLPS0 state.
It should be selected on all Intel platforms supported by the driver.
Supported features:
- SLP_S0_RESIDENCY counter
- PCH IP Power Gating status
- LTR Ignore
- LTR Ignore / LTR Show
- MPHY/PLL gating status (Sunrisepoint PCH only)
- SLPS0 Debug registers (Cannonlake/Icelake PCH)
- Low Power Mode registers (Tigerlake and beyond)
- PMC quirks as needed to enable SLPS0/S0ix
config INTEL_PMT_CLASS
tristate
......
......@@ -185,5 +185,8 @@ void exit_enum_attributes(void)
sysfs_remove_group(wmi_priv.enumeration_data[instance_id].attr_name_kobj,
&enumeration_attr_group);
}
wmi_priv.enumeration_instances_count = 0;
kfree(wmi_priv.enumeration_data);
wmi_priv.enumeration_data = NULL;
}
......@@ -175,5 +175,8 @@ void exit_int_attributes(void)
sysfs_remove_group(wmi_priv.integer_data[instance_id].attr_name_kobj,
&integer_attr_group);
}
wmi_priv.integer_instances_count = 0;
kfree(wmi_priv.integer_data);
wmi_priv.integer_data = NULL;
}
......@@ -183,5 +183,8 @@ void exit_po_attributes(void)
sysfs_remove_group(wmi_priv.po_data[instance_id].attr_name_kobj,
&po_attr_group);
}
wmi_priv.po_instances_count = 0;
kfree(wmi_priv.po_data);
wmi_priv.po_data = NULL;
}
......@@ -155,5 +155,8 @@ void exit_str_attributes(void)
sysfs_remove_group(wmi_priv.str_data[instance_id].attr_name_kobj,
&str_attr_group);
}
wmi_priv.str_instances_count = 0;
kfree(wmi_priv.str_data);
wmi_priv.str_data = NULL;
}
......@@ -210,25 +210,17 @@ static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
*/
static int create_attributes_level_sysfs_files(void)
{
int ret = sysfs_create_file(&wmi_priv.main_dir_kset->kobj, &reset_bios.attr);
int ret;
if (ret) {
pr_debug("could not create reset_bios file\n");
ret = sysfs_create_file(&wmi_priv.main_dir_kset->kobj, &reset_bios.attr);
if (ret)
return ret;
}
ret = sysfs_create_file(&wmi_priv.main_dir_kset->kobj, &pending_reboot.attr);
if (ret) {
pr_debug("could not create changing_pending_reboot file\n");
sysfs_remove_file(&wmi_priv.main_dir_kset->kobj, &reset_bios.attr);
}
return ret;
}
if (ret)
return ret;
static void release_reset_bios_data(void)
{
sysfs_remove_file(&wmi_priv.main_dir_kset->kobj, &reset_bios.attr);
sysfs_remove_file(&wmi_priv.main_dir_kset->kobj, &pending_reboot.attr);
return 0;
}
static ssize_t wmi_sysman_attr_show(struct kobject *kobj, struct attribute *attr,
......@@ -373,8 +365,6 @@ static void destroy_attribute_objs(struct kset *kset)
*/
static void release_attributes_data(void)
{
release_reset_bios_data();
mutex_lock(&wmi_priv.mutex);
exit_enum_attributes();
exit_int_attributes();
......@@ -386,11 +376,13 @@ static void release_attributes_data(void)
wmi_priv.authentication_dir_kset = NULL;
}
if (wmi_priv.main_dir_kset) {
sysfs_remove_file(&wmi_priv.main_dir_kset->kobj, &reset_bios.attr);
sysfs_remove_file(&wmi_priv.main_dir_kset->kobj, &pending_reboot.attr);
destroy_attribute_objs(wmi_priv.main_dir_kset);
kset_unregister(wmi_priv.main_dir_kset);
wmi_priv.main_dir_kset = NULL;
}
mutex_unlock(&wmi_priv.mutex);
}
/**
......@@ -497,7 +489,6 @@ static int init_bios_attributes(int attr_type, const char *guid)
err_attr_init:
mutex_unlock(&wmi_priv.mutex);
release_attributes_data();
kfree(obj);
return retval;
}
......@@ -513,102 +504,91 @@ static int __init sysman_init(void)
}
ret = init_bios_attr_set_interface();
if (ret || !wmi_priv.bios_attr_wdev) {
pr_debug("failed to initialize set interface\n");
goto fail_set_interface;
}
if (ret)
return ret;
ret = init_bios_attr_pass_interface();
if (ret || !wmi_priv.password_attr_wdev) {
pr_debug("failed to initialize pass interface\n");
goto fail_pass_interface;
if (ret)
goto err_exit_bios_attr_set_interface;
if (!wmi_priv.bios_attr_wdev || !wmi_priv.password_attr_wdev) {
pr_debug("failed to find set or pass interface\n");
ret = -ENODEV;
goto err_exit_bios_attr_pass_interface;
}
ret = class_register(&firmware_attributes_class);
if (ret)
goto fail_class;
goto err_exit_bios_attr_pass_interface;
wmi_priv.class_dev = device_create(&firmware_attributes_class, NULL, MKDEV(0, 0),
NULL, "%s", DRIVER_NAME);
if (IS_ERR(wmi_priv.class_dev)) {
ret = PTR_ERR(wmi_priv.class_dev);
goto fail_classdev;
goto err_unregister_class;
}
wmi_priv.main_dir_kset = kset_create_and_add("attributes", NULL,
&wmi_priv.class_dev->kobj);
if (!wmi_priv.main_dir_kset) {
ret = -ENOMEM;
goto fail_main_kset;
goto err_destroy_classdev;
}
wmi_priv.authentication_dir_kset = kset_create_and_add("authentication", NULL,
&wmi_priv.class_dev->kobj);
if (!wmi_priv.authentication_dir_kset) {
ret = -ENOMEM;
goto fail_authentication_kset;
goto err_release_attributes_data;
}
ret = create_attributes_level_sysfs_files();
if (ret) {
pr_debug("could not create reset BIOS attribute\n");
goto fail_reset_bios;
goto err_release_attributes_data;
}
ret = init_bios_attributes(ENUM, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
if (ret) {
pr_debug("failed to populate enumeration type attributes\n");
goto fail_create_group;
goto err_release_attributes_data;
}
ret = init_bios_attributes(INT, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
if (ret) {
pr_debug("failed to populate integer type attributes\n");
goto fail_create_group;
goto err_release_attributes_data;
}
ret = init_bios_attributes(STR, DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
if (ret) {
pr_debug("failed to populate string type attributes\n");
goto fail_create_group;
goto err_release_attributes_data;
}
ret = init_bios_attributes(PO, DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
if (ret) {
pr_debug("failed to populate pass object type attributes\n");
goto fail_create_group;
goto err_release_attributes_data;
}
return 0;
fail_create_group:
err_release_attributes_data:
release_attributes_data();
fail_reset_bios:
if (wmi_priv.authentication_dir_kset) {
kset_unregister(wmi_priv.authentication_dir_kset);
wmi_priv.authentication_dir_kset = NULL;
}
fail_authentication_kset:
if (wmi_priv.main_dir_kset) {
kset_unregister(wmi_priv.main_dir_kset);
wmi_priv.main_dir_kset = NULL;
}
fail_main_kset:
err_destroy_classdev:
device_destroy(&firmware_attributes_class, MKDEV(0, 0));
fail_classdev:
err_unregister_class:
class_unregister(&firmware_attributes_class);
fail_class:
err_exit_bios_attr_pass_interface:
exit_bios_attr_pass_interface();
fail_pass_interface:
err_exit_bios_attr_set_interface:
exit_bios_attr_set_interface();
fail_set_interface:
return ret;
}
......
......@@ -90,6 +90,13 @@ static const struct dmi_system_id button_array_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x2 Detachable"),
},
},
{
.ident = "Lenovo ThinkPad X1 Tablet Gen 2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Tablet Gen 2"),
},
},
{ }
};
......
......@@ -48,8 +48,16 @@ static const struct key_entry intel_vbtn_keymap[] = {
};
static const struct key_entry intel_vbtn_switchmap[] = {
{ KE_SW, 0xCA, { .sw = { SW_DOCK, 1 } } }, /* Docked */
{ KE_SW, 0xCB, { .sw = { SW_DOCK, 0 } } }, /* Undocked */
/*
* SW_DOCK should only be reported for docking stations, but DSDTs using the
* intel-vbtn code, always seem to use this for 2-in-1s / convertibles and set
* SW_DOCK=1 when in laptop-mode (in tandem with setting SW_TABLET_MODE=0).
* This causes userspace to think the laptop is docked to a port-replicator
* and to disable suspend-on-lid-close, which is undesirable.
* Map the dock events to KEY_IGNORE to avoid this broken SW_DOCK reporting.
*/
{ KE_IGNORE, 0xCA, { .sw = { SW_DOCK, 1 } } }, /* Docked */
{ KE_IGNORE, 0xCB, { .sw = { SW_DOCK, 0 } } }, /* Undocked */
{ KE_SW, 0xCC, { .sw = { SW_TABLET_MODE, 1 } } }, /* Tablet */
{ KE_SW, 0xCD, { .sw = { SW_TABLET_MODE, 0 } } }, /* Laptop */
{ KE_END }
......
......@@ -863,34 +863,45 @@ static int pmc_core_pll_show(struct seq_file *s, void *unused)
}
DEFINE_SHOW_ATTRIBUTE(pmc_core_pll);
static ssize_t pmc_core_ltr_ignore_write(struct file *file,
const char __user *userbuf,
size_t count, loff_t *ppos)
static int pmc_core_send_ltr_ignore(u32 value)
{
struct pmc_dev *pmcdev = &pmc;
const struct pmc_reg_map *map = pmcdev->map;
u32 val, buf_size, fd;
int err;
buf_size = count < 64 ? count : 64;
err = kstrtou32_from_user(userbuf, buf_size, 10, &val);
if (err)
return err;
u32 reg;
int err = 0;
mutex_lock(&pmcdev->lock);
if (val > map->ltr_ignore_max) {
if (value > map->ltr_ignore_max) {
err = -EINVAL;
goto out_unlock;
}
fd = pmc_core_reg_read(pmcdev, map->ltr_ignore_offset);
fd |= (1U << val);
pmc_core_reg_write(pmcdev, map->ltr_ignore_offset, fd);
reg = pmc_core_reg_read(pmcdev, map->ltr_ignore_offset);
reg |= BIT(value);
pmc_core_reg_write(pmcdev, map->ltr_ignore_offset, reg);
out_unlock:
mutex_unlock(&pmcdev->lock);
return err;
}
static ssize_t pmc_core_ltr_ignore_write(struct file *file,
const char __user *userbuf,
size_t count, loff_t *ppos)
{
u32 buf_size, value;
int err;
buf_size = min_t(u32, count, 64);
err = kstrtou32_from_user(userbuf, buf_size, 10, &value);
if (err)
return err;
err = pmc_core_send_ltr_ignore(value);
return err == 0 ? count : err;
}
......@@ -1244,6 +1255,15 @@ static int pmc_core_probe(struct platform_device *pdev)
pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit();
dmi_check_system(pmc_core_dmi_table);
/*
* On TGL, due to a hardware limitation, the GBE LTR blocks PC10 when
* a cable is attached. Tell the PMC to ignore it.
*/
if (pmcdev->map == &tgl_reg_map) {
dev_dbg(&pdev->dev, "ignoring GBE LTR\n");
pmc_core_send_ltr_ignore(3);
}
pmc_core_dbgfs_register(pmcdev);
device_initialized = true;
......
......@@ -173,7 +173,7 @@ static int intel_pmt_dev_register(struct intel_pmt_entry *entry,
struct intel_pmt_namespace *ns,
struct device *parent)
{
struct resource res;
struct resource res = {0};
struct device *dev;
int ret;
......
......@@ -23,18 +23,17 @@
#define CRASH_TYPE_OOBMSM 1
/* Control Flags */
#define CRASHLOG_FLAG_DISABLE BIT(27)
#define CRASHLOG_FLAG_DISABLE BIT(28)
/*
* Bits 28 and 29 control the state of bit 31.
* Bits 29 and 30 control the state of bit 31.
*
* Bit 28 will clear bit 31, if set, allowing a new crashlog to be captured.
* Bit 29 will immediately trigger a crashlog to be generated, setting bit 31.
* Bit 30 is read-only and reserved as 0.
* Bit 29 will clear bit 31, if set, allowing a new crashlog to be captured.
* Bit 30 will immediately trigger a crashlog to be generated, setting bit 31.
* Bit 31 is the read-only status with a 1 indicating log is complete.
*/
#define CRASHLOG_FLAG_TRIGGER_CLEAR BIT(28)
#define CRASHLOG_FLAG_TRIGGER_EXECUTE BIT(29)
#define CRASHLOG_FLAG_TRIGGER_CLEAR BIT(29)
#define CRASHLOG_FLAG_TRIGGER_EXECUTE BIT(30)
#define CRASHLOG_FLAG_TRIGGER_COMPLETE BIT(31)
#define CRASHLOG_FLAG_TRIGGER_MASK GENMASK(31, 28)
......
......@@ -4081,13 +4081,19 @@ static bool hotkey_notify_6xxx(const u32 hkey,
case TP_HKEY_EV_KEY_NUMLOCK:
case TP_HKEY_EV_KEY_FN:
case TP_HKEY_EV_KEY_FN_ESC:
/* key press events, we just ignore them as long as the EC
* is still reporting them in the normal keyboard stream */
*send_acpi_ev = false;
*ignore_acpi_ev = true;
return true;
case TP_HKEY_EV_KEY_FN_ESC:
/* Get the media key status to foce the status LED to update */
acpi_evalf(hkey_handle, NULL, "GMKS", "v");
*send_acpi_ev = false;
*ignore_acpi_ev = true;
return true;
case TP_HKEY_EV_TABLET_CHANGED:
tpacpi_input_send_tabletsw();
hotkey_tablet_mode_notify_change();
......@@ -9845,6 +9851,11 @@ static struct ibm_struct lcdshadow_driver_data = {
* Thinkpad sensor interfaces
*/
#define DYTC_CMD_QUERY 0 /* To get DYTC status - enable/revision */
#define DYTC_QUERY_ENABLE_BIT 8 /* Bit 8 - 0 = disabled, 1 = enabled */
#define DYTC_QUERY_SUBREV_BIT 16 /* Bits 16 - 27 - sub revision */
#define DYTC_QUERY_REV_BIT 28 /* Bits 28 - 31 - revision */
#define DYTC_CMD_GET 2 /* To get current IC function and mode */
#define DYTC_GET_LAPMODE_BIT 17 /* Set when in lapmode */
......@@ -9855,6 +9866,7 @@ static bool has_palmsensor;
static bool has_lapsensor;
static bool palm_state;
static bool lap_state;
static int dytc_version;
static int dytc_command(int command, int *output)
{
......@@ -9869,6 +9881,33 @@ static int dytc_command(int command, int *output)
return 0;
}
static int dytc_get_version(void)
{
int err, output;
/* Check if we've been called before - and just return cached value */
if (dytc_version)
return dytc_version;
/* Otherwise query DYTC and extract version information */
err = dytc_command(DYTC_CMD_QUERY, &output);
/*
* If support isn't available (ENODEV) then don't return an error
* and don't create the sysfs group
*/
if (err == -ENODEV)
return 0;
/* For all other errors we can flag the failure */
if (err)
return err;
/* Check DYTC is enabled and supports mode setting */
if (output & BIT(DYTC_QUERY_ENABLE_BIT))
dytc_version = (output >> DYTC_QUERY_REV_BIT) & 0xF;
return 0;
}
static int lapsensor_get(bool *present, bool *state)
{
int output, err;
......@@ -9974,7 +10013,18 @@ static int tpacpi_proxsensor_init(struct ibm_init_struct *iibm)
if (err)
return err;
}
if (has_lapsensor) {
/* Check if we know the DYTC version, if we don't then get it */
if (!dytc_version) {
err = dytc_get_version();
if (err)
return err;
}
/*
* Platforms before DYTC version 5 claim to have a lap sensor, but it doesn't work, so we
* ignore them
*/
if (has_lapsensor && (dytc_version >= 5)) {
err = sysfs_create_file(&tpacpi_pdev->dev.kobj, &dev_attr_dytc_lapmode.attr);
if (err)
return err;
......@@ -9999,14 +10049,9 @@ static struct ibm_struct proxsensor_driver_data = {
* DYTC Platform Profile interface
*/
#define DYTC_CMD_QUERY 0 /* To get DYTC status - enable/revision */
#define DYTC_CMD_SET 1 /* To enable/disable IC function mode */
#define DYTC_CMD_RESET 0x1ff /* To reset back to default */
#define DYTC_QUERY_ENABLE_BIT 8 /* Bit 8 - 0 = disabled, 1 = enabled */
#define DYTC_QUERY_SUBREV_BIT 16 /* Bits 16 - 27 - sub revision */
#define DYTC_QUERY_REV_BIT 28 /* Bits 28 - 31 - revision */
#define DYTC_GET_FUNCTION_BIT 8 /* Bits 8-11 - function setting */
#define DYTC_GET_MODE_BIT 12 /* Bits 12-15 - mode setting */
......@@ -10142,8 +10187,13 @@ static int dytc_profile_set(struct platform_profile_handler *pprof,
return err;
if (profile == PLATFORM_PROFILE_BALANCED) {
/* To get back to balanced mode we just issue a reset command */
err = dytc_command(DYTC_CMD_RESET, &output);
/*
* To get back to balanced mode we need to issue a reset command.
* Note we still need to disable CQL mode before hand and re-enable
* it afterwards, otherwise dytc_lapmode gets reset to 0 and stays
* stuck at 0 for aprox. 30 minutes.
*/
err = dytc_cql_command(DYTC_CMD_RESET, &output);
if (err)
goto unlock;
} else {
......@@ -10211,28 +10261,28 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
if (err)
return err;
/* Check if we know the DYTC version, if we don't then get it */
if (!dytc_version) {
err = dytc_get_version();
if (err)
return err;
}
/* Check DYTC is enabled and supports mode setting */
if (output & BIT(DYTC_QUERY_ENABLE_BIT)) {
/* Only DYTC v5.0 and later has this feature. */
int dytc_version;
dytc_version = (output >> DYTC_QUERY_REV_BIT) & 0xF;
if (dytc_version >= 5) {
dbg_printk(TPACPI_DBG_INIT,
"DYTC version %d: thermal mode available\n", dytc_version);
/* Create platform_profile structure and register */
err = platform_profile_register(&dytc_profile);
/*
* If for some reason platform_profiles aren't enabled
* don't quit terminally.
*/
if (err)
return 0;
if (dytc_version >= 5) {
dbg_printk(TPACPI_DBG_INIT,
"DYTC version %d: thermal mode available\n", dytc_version);
/* Create platform_profile structure and register */
err = platform_profile_register(&dytc_profile);
/*
* If for some reason platform_profiles aren't enabled
* don't quit terminally.
*/
if (err)
return 0;
dytc_profile_available = true;
/* Ensure initial values are correct */
dytc_profile_refresh();
}
dytc_profile_available = true;
/* Ensure initial values are correct */
dytc_profile_refresh();
}
return 0;
}
......
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