From patchwork Thu Nov 23 00:48:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Armin Wolf X-Patchwork-Id: 168656 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:6358:6f03:b0:164:83eb:24d7 with SMTP id r3csp1606707rwn; Wed, 22 Nov 2023 16:49:57 -0800 (PST) X-Google-Smtp-Source: AGHT+IEYNxMjMagLJUiqY865kWLVwzZZfy9Ox0icOtzeM5flGOGLmAgWuWv56AM99V3D6ahNuSJ2 X-Received: by 2002:a17:90b:1d92:b0:27d:5964:4ee6 with SMTP id pf18-20020a17090b1d9200b0027d59644ee6mr4494860pjb.2.1700700596754; Wed, 22 Nov 2023 16:49:56 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1700700596; cv=none; d=google.com; s=arc-20160816; b=rKdLli7uXDArr20WAUuYQhxo7oCXhUut688hwHUFiEnumwCg0dEq7E+aE8nu1SkCWF rbPA5tyt+v8l+6CH4bRowbR+ORCD9diSWkeCkf1puxZiYiMK9mYW+2b5PFW+4ZB1Z9+c 7WPSS5Oh8Z+RgpmuGGs7QqNCNfab2b27et6ceIRoxDVvdV4xK1R+NKr9bsqI93Hm+Qyh YAfYYQPZTWh0T71RWV6xX87CIrJxjvp7VTt5HkHK3sjwVjHhK3k4sXzC9uVmml5zEFqU lSppiz0jaCkevYY0SmxPU/dQrFFG/NL5YV8Rp7DreiLGb8PR24h0w58CqFfClAghCuby uaWw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:ui-outboundreport:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=QFDrrUDVWa6EgG6y99RTVMcOx+FMIfObxWok4DuPzh8=; fh=LbJc+26ESPHxBsYHQvEuE116sbQvfgEPUOE2p6r6f4A=; b=IJvcG4b88WFwvuvwyQqzdImxcCXosrmyQ9jnXafds5IMA0TLyzmnNTp9iI2wTMdXy8 YuvnkGVnZ3zzRebAgBwqzrlWDqnv4UUlZYUbvHv/nJJF6t8tFLuTU5jOimAarHWQEiIb pY+Ex2W5vaRRkYXWvIMlF0qol0PWVuKDQP4uPu4BBXOvxEY4kS5Ud96gPlKnzEO743b4 /VYKjDgtrGEC0LHwNItK6cEc3gtXvsyTI7adJKz5Hl9qQN46N+9BXZUzmc5hxFzuskjB 7vnfxCLG0bywgNCIgBR7Khm1wIgoEp3tlcVx85IsquQnlvOXCQxxY+nd2Uva6zKXJa6+ OAAA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmx.de header.s=s31663417 header.b=b4YZg92r; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:7 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gmx.de Received: from snail.vger.email (snail.vger.email. [2620:137:e000::3:7]) by mx.google.com with ESMTPS id pf7-20020a17090b1d8700b002801ac582d0si227247pjb.185.2023.11.22.16.49.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 22 Nov 2023 16:49:56 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:7 as permitted sender) client-ip=2620:137:e000::3:7; Authentication-Results: mx.google.com; dkim=pass header.i=@gmx.de header.s=s31663417 header.b=b4YZg92r; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:7 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gmx.de Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by snail.vger.email (Postfix) with ESMTP id 10626829BC46; Wed, 22 Nov 2023 16:49:55 -0800 (PST) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.11 at snail.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235215AbjKWAtw (ORCPT + 99 others); Wed, 22 Nov 2023 19:49:52 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39366 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233574AbjKWAtg (ORCPT ); Wed, 22 Nov 2023 19:49:36 -0500 Received: from mout.gmx.net (mout.gmx.net [212.227.17.22]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B50CA10D4; Wed, 22 Nov 2023 16:49:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.de; s=s31663417; t=1700700528; x=1701305328; i=w_armin@gmx.de; bh=QU/fikrXASrkJJFGObsA5vw2cS6jYRUC5rQHjgXzBWY=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:In-Reply-To: References; b=b4YZg92rZpXgWJwHyQaR89wsr6f1h5YT6xXq9koJ8NUf2t3+yNv2Ee4mVbtS4Boq swCa1tA7lUof4Gh+I4x0wBL4JPMGFSm91JyD56H4Kbo6VuzYLGW3m0Zy9gXA0/iwa NnQ1UVfSKP8++1mRS+oyedZw2JfgYZnSvjNCUdKtXsmU2z/QHK3r3n9YH+RsRP29Q c46zL1Z5/TXyOB7NSQhfGqRpemP56qZCguceI2pYG3R2Iv4LUOGKv5gFgyDjCdXj0 C2kdU/W/FbvDNiUmQMToL6YRwqfibHJq+yEIXOxOHkJjF3iG/ILl5sKVKYmyBGE8G Ajvq8HvG6yhX2YqGSQ== X-UI-Sender-Class: 724b4f7f-cbec-4199-ad4e-598c01a50d3a Received: from mx-amd-b650.users.agdsn.de ([141.30.226.129]) by mail.gmx.net (mrgmx105 [212.227.17.168]) with ESMTPSA (Nemesis) id 1N0oBx-1rII7B24mr-00wjHn; Thu, 23 Nov 2023 01:48:48 +0100 From: Armin Wolf To: pali@kernel.org Cc: jdelvare@suse.com, linux@roeck-us.net, hdegoede@redhat.com, markgross@kernel.org, ilpo.jarvinen@linux.intel.com, platform-driver-x86@vger.kernel.org, linux-hwmon@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 7/9] hwmon: (dell-smm) Add support for WMI SMM interface Date: Thu, 23 Nov 2023 01:48:18 +0100 Message-Id: <20231123004820.50635-8-W_Armin@gmx.de> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231123004820.50635-1-W_Armin@gmx.de> References: <20231123004820.50635-1-W_Armin@gmx.de> MIME-Version: 1.0 X-Provags-ID: V03:K1:s1fMuo2wdlUW/5cyisDKRKTpMoW1C50KaQRYjugB04Y38gSWsU8 7P8sq9WhM2+3rsbHCb9g8lZwBM2WEI3ZRjLHrtfyWAtDU38RKqBso6u3m4kswo3f4RAODp0 TQ1hgfwwAzkvGGqJRon3F6edzvpmUQ2YAaemBcjjHlX8S8vLoBAbNSgaLXc115rcpTyhPS7 GHPsrxazmZoSjTSpLIWVg== UI-OutboundReport: notjunk:1;M01:P0:3vOS++G1dgY=;wy8NRIj7z5aVgjPDv0vEW0b2w7C PuVP5Z5KzEDM8xqt/F10e02U6GeOuPqeJycaxqr2e/V8wrsyklQgzs9boVgdRdNgEi0JawhaG jJfnZy9/b3B501rxYtyBmVNH1ljouadUK2RAJinCrJe3tWkHcin5gw1+3Ubo5adSjByO7QNEE lcktU1SNkbmIsYq6zDUhmhG5s4juRX6DptcROQMcA0IoCyuFU71kJZM1nGZf2SqWOVYqbiEmL urPLvxyUV0848KU0cxciKeIYjS1odUI3gF340MjAWIVASRkxpmyMtJbnwr9JiMDsjAqsgz8q6 s1qcaCwWP5qtVYXkEC6FiG17GqQtb3QptSV/6TSMmLipwAgh0dBePAv4dm1r5+fdBF3g6rNTK 99pKhOGb+1PlinjNmzzkIefQwuHtc5u27cVk9dDm0+nsAzSieWNiNIlnhW6JkC6Cbm8KdHTGG TM9ru/R4/DAOu4F6Alwv+868WA4EHJmoJtityBWqZ7DmehXBV05iiVkH05GtiAHDw9QE0b2M+ KuJkObNNParkwB/EdBcRw4JaGifrR5/n2gPJs31D5IPXqcoZLD1j3kuXrVS4IodxlZlaO21iY h8804gZmiOIONPg27DMZ0Jo9tsn5YIevsRzm3CTmcu1exV/Wk64EXrgK6aJpkYRCGCC8Qdrx2 fo/cH6WKruvVpNLCfNcSBCP+KRsWE7xy4VsV0Y8C4jT0EbTsxIZObrMWI1ZxxsF8eh3635jOx f4kJulMvWUg0gE3XVp3sgWY5mTXgXRvlfA+FROA1//uymtK55BC7wGpHXcudb3SE9ERxJPD/R Sv0k2Lr3bB+R5XqwCsTx3IDq8GZLCpA3klFxATjLpi5Y1FfiPbG3Nif+jX1TZo8zmQgDkeUCk QGk8jZsO1O2swo/1KsAdfqKC4bqGdChcR5quyUYQoyLJEp5plJK7VU3umIJMvncyGuVMRbe0d k13ylPMSjClPR2K2OLsoDVJmEgM= X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM, RCVD_IN_DNSWL_BLOCKED,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (snail.vger.email [0.0.0.0]); Wed, 22 Nov 2023 16:49:55 -0800 (PST) X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1783313807299390310 X-GMAIL-MSGID: 1783313829224473468 Some Dell machines like the Dell Optiplex 7000 do not support the legacy SMM interface, but instead expect all SMM calls to be issued over a special WMI interface. Add support for this interface so users can control the fans on those machines. Tested-by: Reviewed-by: Hans de Goede Signed-off-by: Armin Wolf --- drivers/hwmon/Kconfig | 1 + drivers/hwmon/dell-smm-hwmon.c | 199 +++++++++++++++++++++++++++++---- drivers/platform/x86/wmi.c | 1 + 3 files changed, 182 insertions(+), 19 deletions(-) -- 2.39.2 diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index cf27523eed5a..76cb05db1dcf 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -512,6 +512,7 @@ config SENSORS_DS1621 config SENSORS_DELL_SMM tristate "Dell laptop SMM BIOS hwmon driver" + depends on ACPI_WMI depends on X86 imply THERMAL help diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index a377cd08355f..95330437c5af 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -12,6 +12,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -34,8 +35,10 @@ #include #include #include +#include #include +#include #define I8K_SMM_FN_STATUS 0x0025 #define I8K_SMM_POWER_STATUS 0x0069 @@ -66,6 +69,9 @@ #define I8K_POWER_AC 0x05 #define I8K_POWER_BATTERY 0x01 +#define DELL_SMM_WMI_GUID "F1DDEE52-063C-4784-A11E-8A06684B9B01" +#define DELL_SMM_LEGACY_EXECUTE 0x1 + #define DELL_SMM_NO_TEMP 10 #define DELL_SMM_NO_FANS 3 @@ -219,6 +225,103 @@ static const struct dell_smm_ops i8k_smm_ops = { .smm_call = i8k_smm_call, }; +/* + * Call the System Management Mode BIOS over WMI. + */ +static ssize_t wmi_parse_register(u8 *buffer, u32 length, unsigned int *reg) +{ + __le32 value; + u32 reg_size; + + if (length <= sizeof(reg_size)) + return -ENODATA; + + reg_size = get_unaligned_le32(buffer); + if (!reg_size || reg_size > sizeof(value)) + return -ENOMSG; + + if (length < sizeof(reg_size) + reg_size) + return -ENODATA; + + memcpy_and_pad(&value, sizeof(value), buffer + sizeof(reg_size), reg_size, 0); + *reg = le32_to_cpu(value); + + return reg_size + sizeof(reg_size); +} + +static int wmi_parse_response(u8 *buffer, u32 length, struct smm_regs *regs) +{ + unsigned int *registers[] = { + ®s->eax, + ®s->ebx, + ®s->ecx, + ®s->edx + }; + u32 offset = 0; + ssize_t ret; + int i; + + for (i = 0; i < ARRAY_SIZE(registers); i++) { + if (offset >= length) + return -ENODATA; + + ret = wmi_parse_register(buffer + offset, length - offset, registers[i]); + if (ret < 0) + return ret; + + offset += ret; + } + + if (offset != length) + return -ENOMSG; + + return 0; +} + +static int wmi_smm_call(struct device *dev, struct smm_regs *regs) +{ + struct wmi_device *wdev = container_of(dev, struct wmi_device, dev); + struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; + u32 wmi_payload[] = { + sizeof(regs->eax), + regs->eax, + sizeof(regs->ebx), + regs->ebx, + sizeof(regs->ecx), + regs->ecx, + sizeof(regs->edx), + regs->edx + }; + const struct acpi_buffer in = { + .length = sizeof(wmi_payload), + .pointer = &wmi_payload, + }; + union acpi_object *obj; + acpi_status status; + int ret; + + status = wmidev_evaluate_method(wdev, 0x0, DELL_SMM_LEGACY_EXECUTE, &in, &out); + if (ACPI_FAILURE(status)) + return -EIO; + + obj = out.pointer; + if (!obj) + return -ENODATA; + + if (obj->type != ACPI_TYPE_BUFFER) { + ret = -ENOMSG; + + goto err_free; + } + + ret = wmi_parse_response(obj->buffer.pointer, obj->buffer.length, regs); + +err_free: + kfree(obj); + + return ret; +} + static int dell_smm_call(const struct dell_smm_ops *ops, struct smm_regs *regs) { unsigned int eax = regs->eax; @@ -306,7 +409,7 @@ static int i8k_get_fan_type(struct dell_smm_data *data, u8 fan) /* * Read the fan nominal rpm for specific fan speed. */ -static int __init i8k_get_fan_nominal_speed(const struct dell_smm_data *data, u8 fan, int speed) +static int i8k_get_fan_nominal_speed(const struct dell_smm_data *data, u8 fan, int speed) { struct smm_regs regs = { .eax = I8K_SMM_GET_NOM_SPEED, @@ -349,7 +452,7 @@ static int i8k_set_fan(const struct dell_smm_data *data, u8 fan, int speed) return dell_smm_call(data->ops, ®s); } -static int __init i8k_get_temp_type(const struct dell_smm_data *data, u8 sensor) +static int i8k_get_temp_type(const struct dell_smm_data *data, u8 sensor) { struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP_TYPE, @@ -401,7 +504,7 @@ static int i8k_get_temp(const struct dell_smm_data *data, u8 sensor) return temp; } -static int __init dell_smm_get_signature(const struct dell_smm_ops *ops, int req_fn) +static int dell_smm_get_signature(const struct dell_smm_ops *ops, int req_fn) { struct smm_regs regs = { .eax = req_fn, }; int rc; @@ -986,7 +1089,7 @@ static const struct hwmon_chip_info dell_smm_chip_info = { .info = dell_smm_info, }; -static int __init dell_smm_init_cdev(struct device *dev, u8 fan_num) +static int dell_smm_init_cdev(struct device *dev, u8 fan_num) { struct dell_smm_data *data = dev_get_drvdata(dev); struct thermal_cooling_device *cdev; @@ -1017,7 +1120,7 @@ static int __init dell_smm_init_cdev(struct device *dev, u8 fan_num) return ret; } -static int __init dell_smm_init_hwmon(struct device *dev) +static int dell_smm_init_hwmon(struct device *dev) { struct dell_smm_data *data = dev_get_drvdata(dev); struct device *dell_smm_hwmon_dev; @@ -1083,7 +1186,7 @@ static int __init dell_smm_init_hwmon(struct device *dev) return PTR_ERR_OR_ZERO(dell_smm_hwmon_dev); } -static int __init dell_smm_init_data(struct device *dev, const struct dell_smm_ops *ops) +static int dell_smm_init_data(struct device *dev, const struct dell_smm_ops *ops) { struct dell_smm_data *data; @@ -1409,6 +1512,9 @@ static const struct dmi_system_id i8k_whitelist_fan_control[] __initconst = { { } }; +/* + * Legacy SMM backend driver. + */ static int __init dell_smm_probe(struct platform_device *pdev) { int ret; @@ -1434,6 +1540,47 @@ static struct platform_driver dell_smm_driver = { static struct platform_device *dell_smm_device; +/* + * WMI SMM backend driver. + */ +static int dell_smm_wmi_probe(struct wmi_device *wdev, const void *context) +{ + struct dell_smm_ops *ops; + int ret; + + ops = devm_kzalloc(&wdev->dev, sizeof(*ops), GFP_KERNEL); + if (!ops) + return -ENOMEM; + + ops->smm_call = wmi_smm_call; + ops->smm_dev = &wdev->dev; + + if (dell_smm_get_signature(ops, I8K_SMM_GET_DELL_SIG1) && + dell_smm_get_signature(ops, I8K_SMM_GET_DELL_SIG2)) + return -ENODEV; + + ret = dell_smm_init_data(&wdev->dev, ops); + if (ret < 0) + return ret; + + return dell_smm_init_hwmon(&wdev->dev); +} + +static const struct wmi_device_id dell_smm_wmi_id_table[] = { + { DELL_SMM_WMI_GUID, NULL }, + { } +}; +MODULE_DEVICE_TABLE(wmi, dell_smm_wmi_id_table); + +static struct wmi_driver dell_smm_wmi_driver = { + .driver = { + .name = KBUILD_MODNAME, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .id_table = dell_smm_wmi_id_table, + .probe = dell_smm_wmi_probe, +}; + /* * Probe for the presence of a supported laptop. */ @@ -1485,33 +1632,43 @@ static void __init dell_smm_init_dmi(void) } } -static int __init i8k_init(void) +static int __init dell_smm_legacy_check(void) { - /* - * Get DMI information - */ if (!dmi_check_system(i8k_dmi_table)) { if (!ignore_dmi && !force) return -ENODEV; - pr_info("not running on a supported Dell system.\n"); + pr_info("Probing for legacy SMM handler on unsupported machine\n"); pr_info("vendor=%s, model=%s, version=%s\n", i8k_get_dmi_data(DMI_SYS_VENDOR), i8k_get_dmi_data(DMI_PRODUCT_NAME), i8k_get_dmi_data(DMI_BIOS_VERSION)); } - dell_smm_init_dmi(); - - /* - * Get SMM Dell signature - */ if (dell_smm_get_signature(&i8k_smm_ops, I8K_SMM_GET_DELL_SIG1) && dell_smm_get_signature(&i8k_smm_ops, I8K_SMM_GET_DELL_SIG2)) { if (!force) return -ENODEV; - pr_err("Unable to get Dell SMM signature\n"); + pr_warn("Forcing legacy SMM calls on a possibly incompatible machine\n"); + } + + return 0; +} + +static int __init i8k_init(void) +{ + int ret; + + dell_smm_init_dmi(); + + ret = dell_smm_legacy_check(); + if (ret < 0) { + /* + * On modern machines, SMM communication happens over WMI, meaning + * the SMM handler might not react to legacy SMM calls. + */ + return wmi_driver_register(&dell_smm_wmi_driver); } dell_smm_device = platform_create_bundle(&dell_smm_driver, dell_smm_probe, NULL, 0, NULL, @@ -1522,8 +1679,12 @@ static int __init i8k_init(void) static void __exit i8k_exit(void) { - platform_device_unregister(dell_smm_device); - platform_driver_unregister(&dell_smm_driver); + if (dell_smm_device) { + platform_device_unregister(dell_smm_device); + platform_driver_unregister(&dell_smm_driver); + } else { + wmi_driver_unregister(&dell_smm_wmi_driver); + } } module_init(i8k_init); diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 5c27b4aa9690..d68a96a2c570 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -106,6 +106,7 @@ MODULE_DEVICE_TABLE(acpi, wmi_device_ids); static const char * const allow_duplicates[] = { "05901221-D566-11D1-B2F0-00A0C9062910", /* wmi-bmof */ "8A42EA14-4F2A-FD45-6422-0087F7A7E608", /* dell-wmi-ddv */ + "F1DDEE52-063C-4784-A11E-8A06684B9B01", /* dell-smm-hwmon */ NULL };