summaryrefslogtreecommitdiff
path: root/drivers/platform/x86/think-lmi.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-07-01 00:50:00 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2023-07-01 00:50:00 +0300
commit9c3255a8f3946a4c8844f1e2e093313f3b71cb30 (patch)
tree5ca0e29c41444c96406a3ed4874800300de69d8e /drivers/platform/x86/think-lmi.c
parent6cdbb0907a3c562723455e351c940037bdec9b7a (diff)
parentd2a7bd3690990ab8a8239096ee432ad51985d5b6 (diff)
downloadlinux-9c3255a8f3946a4c8844f1e2e093313f3b71cb30.tar.xz
Merge tag 'platform-drivers-x86-v6.5-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86
Pull x86 platform driver updates from Hans de Goede: "AMD PMC and PMF drivers: - Various bugfixes - Improved debugging support Intel PMC: - Refactor to support hw with multiple PMCs - Various other improvements / new hw support Intel Speed Select Technology (ISST): - TPMI Uncore Frequency + Cluster Level Power Controls - Various bugfixes - tools/intel-speed-select: Misc improvements Dell-DDV: Add documentation INT3472 ACPI camera sensor glue code: - Evaluate device's _DSM method to control imaging clock - Drop the need to have a table with per sensor-model info Lenovo Yogabook: - Refactor / rework to also support Android models Think-LMI: - Multiple improvements and fixes WMI: - Add proper API documentation for the WMI bus x86-android-tablets: - Misc new hw support Miscellaneous other cleanups / fixes" * tag 'platform-drivers-x86-v6.5-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (91 commits) platform/x86:intel/pmc: Add Meteor Lake IOE-M PMC related maps platform/x86:intel/pmc: Add Meteor Lake IOE-P PMC related maps platform/x86:intel/pmc: Use SSRAM to discover pwrm base address of primary PMC platform/x86:intel/pmc: Discover PMC devices platform/x86:intel/pmc: Enable debugfs multiple PMC support platform/x86:intel/pmc: Add support to handle multiple PMCs platform/x86:intel/pmc: Combine core_init() and core_configure() platform/x86:intel/pmc: Update maps for Meteor Lake P/M platforms platform/x86/intel: tpmi: Remove hardcoded unit and offset platform/x86: int3472: discrete: Log a warning if the pin-numbers don't match platform/x86: int3472: discrete: Use FIELD_GET() on the GPIO _DSM return value platform/x86: int3472: discrete: Add alternative "AVDD" regulator supply name platform/x86: int3472: discrete: Add support for 1 GPIO regulator shared between 2 sensors platform/x86: int3472: discrete: Remove sensor_config-s platform/x86: int3472: discrete: Drop GPIO remapping support platform/x86: apple-gmux: don't use be32_to_cpu and cpu_to_be32 platform/x86/dell/dell-rbtn: Fix resources leaking on error path platform/x86: ISST: Fix usage counter platform/x86: ISST: Reset default callback on unregister platform/x86: int3472: Switch back to use struct i2c_driver's .probe() ...
Diffstat (limited to 'drivers/platform/x86/think-lmi.c')
-rw-r--r--drivers/platform/x86/think-lmi.c65
1 files changed, 55 insertions, 10 deletions
diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c
index 1138f770149d..52d1ce8dfe44 100644
--- a/drivers/platform/x86/think-lmi.c
+++ b/drivers/platform/x86/think-lmi.c
@@ -14,6 +14,7 @@
#include <linux/acpi.h>
#include <linux/errno.h>
#include <linux/fs.h>
+#include <linux/mutex.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/dmi.h>
@@ -168,11 +169,11 @@ MODULE_PARM_DESC(debug_support, "Enable debug command support");
*/
#define LENOVO_CERT_THUMBPRINT_GUID "C59119ED-1C0D-4806-A8E9-59AA318176C4"
-#define TLMI_POP_PWD (1 << 0)
-#define TLMI_PAP_PWD (1 << 1)
-#define TLMI_HDD_PWD (1 << 2)
-#define TLMI_SYS_PWD (1 << 3)
-#define TLMI_CERT (1 << 7)
+#define TLMI_POP_PWD BIT(0) /* Supervisor */
+#define TLMI_PAP_PWD BIT(1) /* Power-on */
+#define TLMI_HDD_PWD BIT(2) /* HDD/NVME */
+#define TLMI_SMP_PWD BIT(6) /* System Management */
+#define TLMI_CERT BIT(7) /* Certificate Based */
#define to_tlmi_pwd_setting(kobj) container_of(kobj, struct tlmi_pwd_setting, kobj)
#define to_tlmi_attr_setting(kobj) container_of(kobj, struct tlmi_attr_setting, kobj)
@@ -195,6 +196,7 @@ static const char * const level_options[] = {
};
static struct think_lmi tlmi_priv;
static struct class *fw_attr_class;
+static DEFINE_MUTEX(tlmi_mutex);
/* ------ Utility functions ------------*/
/* Strip out CR if one is present */
@@ -437,6 +439,9 @@ static ssize_t new_password_store(struct kobject *kobj,
/* Strip out CR if one is present, setting password won't work if it is present */
strip_cr(new_pwd);
+ /* Use lock in case multiple WMI operations needed */
+ mutex_lock(&tlmi_mutex);
+
pwdlen = strlen(new_pwd);
/* pwdlen == 0 is allowed to clear the password */
if (pwdlen && ((pwdlen < setting->minlen) || (pwdlen > setting->maxlen))) {
@@ -456,9 +461,9 @@ static ssize_t new_password_store(struct kobject *kobj,
sprintf(pwd_type, "mhdp%d", setting->index);
} else if (setting == tlmi_priv.pwd_nvme) {
if (setting->level == TLMI_LEVEL_USER)
- sprintf(pwd_type, "unvp%d", setting->index);
+ sprintf(pwd_type, "udrp%d", setting->index);
else
- sprintf(pwd_type, "mnvp%d", setting->index);
+ sprintf(pwd_type, "adrp%d", setting->index);
} else {
sprintf(pwd_type, "%s", setting->pwd_type);
}
@@ -493,6 +498,7 @@ static ssize_t new_password_store(struct kobject *kobj,
kfree(auth_str);
}
out:
+ mutex_unlock(&tlmi_mutex);
kfree(new_pwd);
return ret ?: count;
}
@@ -879,6 +885,11 @@ static umode_t auth_attr_is_visible(struct kobject *kobj,
return 0;
}
+ /* Don't display un-needed settings if opcode available */
+ if ((attr == &auth_encoding.attr || attr == &auth_kbdlang.attr) &&
+ tlmi_priv.opcode_support)
+ return 0;
+
return attr->mode;
}
@@ -981,6 +992,9 @@ static ssize_t current_value_store(struct kobject *kobj,
/* Strip out CR if one is present */
strip_cr(new_setting);
+ /* Use lock in case multiple WMI operations needed */
+ mutex_lock(&tlmi_mutex);
+
/* Check if certificate authentication is enabled and active */
if (tlmi_priv.certificate_support && tlmi_priv.pwd_admin->cert_installed) {
if (!tlmi_priv.pwd_admin->signature || !tlmi_priv.pwd_admin->save_signature) {
@@ -1001,7 +1015,33 @@ static ssize_t current_value_store(struct kobject *kobj,
tlmi_priv.pwd_admin->save_signature);
if (ret)
goto out;
- } else { /* Non certiifcate based authentication */
+ } else if (tlmi_priv.opcode_support) {
+ /*
+ * If opcode support is present use that interface.
+ * Note - this sets the variable and then the password as separate
+ * WMI calls. Function tlmi_save_bios_settings will error if the
+ * password is incorrect.
+ */
+ set_str = kasprintf(GFP_KERNEL, "%s,%s;", setting->display_name,
+ new_setting);
+ if (!set_str) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = tlmi_simple_call(LENOVO_SET_BIOS_SETTINGS_GUID, set_str);
+ if (ret)
+ goto out;
+
+ if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
+ ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin",
+ tlmi_priv.pwd_admin->password);
+ if (ret)
+ goto out;
+ }
+
+ ret = tlmi_save_bios_settings("");
+ } else { /* old non-opcode based authentication method (deprecated) */
if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;",
tlmi_priv.pwd_admin->password,
@@ -1039,6 +1079,7 @@ static ssize_t current_value_store(struct kobject *kobj,
kobject_uevent(&tlmi_priv.class_dev->kobj, KOBJ_CHANGE);
}
out:
+ mutex_unlock(&tlmi_mutex);
kfree(auth_str);
kfree(set_str);
kfree(new_setting);
@@ -1483,11 +1524,11 @@ static int tlmi_analyze(void)
tlmi_priv.pwd_power->valid = true;
if (tlmi_priv.opcode_support) {
- tlmi_priv.pwd_system = tlmi_create_auth("sys", "system");
+ tlmi_priv.pwd_system = tlmi_create_auth("smp", "system");
if (!tlmi_priv.pwd_system)
goto fail_clear_attr;
- if (tlmi_priv.pwdcfg.core.password_state & TLMI_SYS_PWD)
+ if (tlmi_priv.pwdcfg.core.password_state & TLMI_SMP_PWD)
tlmi_priv.pwd_system->valid = true;
tlmi_priv.pwd_hdd = tlmi_create_auth("hdd", "hdd");
@@ -1498,6 +1539,10 @@ static int tlmi_analyze(void)
if (!tlmi_priv.pwd_nvme)
goto fail_clear_attr;
+ /* Set default hdd/nvme index to 1 as there is no device 0 */
+ tlmi_priv.pwd_hdd->index = 1;
+ tlmi_priv.pwd_nvme->index = 1;
+
if (tlmi_priv.pwdcfg.core.password_state & TLMI_HDD_PWD) {
/* Check if PWD is configured and set index to first drive found */
if (tlmi_priv.pwdcfg.ext.hdd_user_password ||