From patchwork Thu Sep 28 04:02:14 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Limonciello, Mario" X-Patchwork-Id: 9975281 X-Patchwork-Delegate: dvhart@infradead.org Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 8A15760365 for ; Thu, 28 Sep 2017 04:03:45 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7A68D2942E for ; Thu, 28 Sep 2017 04:03:45 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6F3C92943A; Thu, 28 Sep 2017 04:03:45 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C2CB22942E for ; Thu, 28 Sep 2017 04:03:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751832AbdI1EDY (ORCPT ); Thu, 28 Sep 2017 00:03:24 -0400 Received: from esa7.dell-outbound.iphmx.com ([68.232.153.96]:39623 "EHLO esa7.dell-outbound.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751219AbdI1EC3 (ORCPT ); Thu, 28 Sep 2017 00:02:29 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=dell.com; i=@dell.com; q=dns/txt; s=smtpout; t=1506570840; x=1538106840; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=Pai3OBEo2V54TWLuyk/o+QMGOIIKpAq94hygkZ2wqO0=; b=Qk7Za8aLrsYu1SMwLLQEyKA2jF1LSvCYLPEq7E7eVfd6b5jcJvHflHWj UCSAzbUfc7rG0Gpj9fT4AuPyvpyAo4eY1PYKXSaINkCdWPaN3ZnNaFlwX 6GwAgMJ9cQlehoyw6qC1jfSAp24Yyd8//7n9Grb+Lv3fV4OmiY9LnU7Ei Y=; Received: from esa1.dell-outbound2.iphmx.com ([68.232.153.201]) by esa7.dell-outbound.iphmx.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 27 Sep 2017 22:53:59 -0500 Received: from ausxipps310.us.dell.com ([143.166.148.211]) by esa1.dell-outbound2.iphmx.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 28 Sep 2017 10:00:21 +0600 X-LoopCount0: from 10.208.86.39 X-IronPort-AV: E=Sophos;i="5.42,448,1500958800"; d="scan'208";a="66774550" X-DLP: DLP_GlobalPCIDSS From: Mario Limonciello To: dvhart@infradead.org, Andy Shevchenko Cc: LKML , platform-driver-x86@vger.kernel.org, Andy Lutomirski , quasisec@google.com, pali.rohar@gmail.com, Mario Limonciello Subject: [PATCH v3 2/8] platform/x86: dell-smbios: Introduce a WMI-ACPI interface Date: Wed, 27 Sep 2017 23:02:14 -0500 Message-Id: <7b632baafbfdc6c55c4d56225c54fd441b747286.1506571188.git.mario.limonciello@dell.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: MIME-Version: 1.0 In-Reply-To: References: Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The driver currently uses an SMI interface which grants direct access to physical memory to the firmware SMM methods via a pointer. Now add a WMI-ACPI interface that is detected by WMI probe and preferred over the SMI interface. Changing this to operate over WMI-ACPI will use an ACPI OperationRegion for a buffer of data storage when SMM calls are performed. This is a safer approach to use in kernel drivers as the SMM will only have access to that OperationRegion. As a result, this change removes the dependency on this driver on the dcdbas kernel module. It's now an optional compilation option. When modifying this, add myself to MAINTAINERS. Signed-off-by: Mario Limonciello --- MAINTAINERS | 6 ++ drivers/platform/x86/Kconfig | 14 ++-- drivers/platform/x86/dell-smbios.c | 128 ++++++++++++++++++++++++++++++++----- drivers/platform/x86/dell-smbios.h | 15 ++++- 4 files changed, 138 insertions(+), 25 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 08b96f77f618..6d76b09f46cc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3990,6 +3990,12 @@ S: Maintained F: drivers/hwmon/dell-smm-hwmon.c F: include/uapi/linux/i8k.h +DELL SMBIOS DRIVER +M: Pali Rohár +M: Mario Limonciello +S: Maintained +F: drivers/platform/x86/dell-smbios.* + DELL SYSTEMS MANAGEMENT BASE DRIVER (dcdbas) M: Doug Warzecha S: Maintained diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 1f7959ff055c..415886d7a857 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -92,13 +92,17 @@ config ASUS_LAPTOP If you have an ACPI-compatible ASUS laptop, say Y or M here. config DELL_SMBIOS - tristate - select DCDBAS + tristate "Dell SMBIOS calling interface" + depends on ACPI_WMI ---help--- - This module provides common functions for kernel modules using - Dell SMBIOS. + This module provides common functions for kernel modules and + userspace using Dell SMBIOS. + + If you have a Dell computer, say Y or M here. - If you have a Dell laptop, say Y or M here. + If you have a machine from < 2007 without a WMI interface you + may also want to enable CONFIG_DCDBAS to allow this driver to + work. config DELL_LAPTOP tristate "Dell Laptop Extras" diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index e9b1ca07c872..4472817ee045 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -4,6 +4,7 @@ * Copyright (c) Red Hat * Copyright (c) 2014 Gabriele Mazzotta * Copyright (c) 2014 Pali Rohár + * Copyright (c) 2017 Dell Inc. * * Based on documentation in the libsmbios package: * Copyright (C) 2005-2014 Dell Inc. @@ -22,9 +23,15 @@ #include #include #include -#include "../../firmware/dcdbas.h" +#include #include "dell-smbios.h" +#ifdef CONFIG_DCDBAS +#include "../../firmware/dcdbas.h" +#endif + +#define DELL_WMI_SMBIOS_GUID "A80593CE-A997-11DA-B012-B622A1EF5492" + struct calling_interface_structure { struct dmi_header header; u16 cmdIOAddress; @@ -33,12 +40,14 @@ struct calling_interface_structure { struct calling_interface_token tokens[]; } __packed; -static struct calling_interface_buffer *buffer; +static void *buffer; +static size_t bufferlen; static DEFINE_MUTEX(buffer_mutex); static int da_command_address; static int da_command_code; static int da_num_tokens; +struct wmi_device *wmi_dev; static struct calling_interface_token *da_tokens; int dell_smbios_error(int value) @@ -60,13 +69,15 @@ struct calling_interface_buffer *dell_smbios_get_buffer(void) { mutex_lock(&buffer_mutex); dell_smbios_clear_buffer(); + if (wmi_dev) + return &((struct wmi_calling_interface_buffer *) buffer)->smi; return buffer; } EXPORT_SYMBOL_GPL(dell_smbios_get_buffer); void dell_smbios_clear_buffer(void) { - memset(buffer, 0, sizeof(struct calling_interface_buffer)); + memset(buffer, 0, bufferlen); } EXPORT_SYMBOL_GPL(dell_smbios_clear_buffer); @@ -76,7 +87,36 @@ void dell_smbios_release_buffer(void) } EXPORT_SYMBOL_GPL(dell_smbios_release_buffer); -void dell_smbios_send_request(int class, int select) +static int run_wmi_smbios_call(struct wmi_calling_interface_buffer *buf) +{ + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; + struct acpi_buffer input; + union acpi_object *obj; + acpi_status status; + + input.length = sizeof(struct wmi_calling_interface_buffer); + input.pointer = buf; + + status = wmidev_evaluate_method(wmi_dev, 0, 1, &input, &output); + if (ACPI_FAILURE(status)) { + pr_err("%x/%x [%x,%x,%x,%x] call failed\n", + buf->smi.class, buf->smi.select, + buf->smi.input[0], buf->smi.input[1], + buf->smi.input[2], buf->smi.input[3]); + return -EIO; + } + obj = (union acpi_object *)output.pointer; + if (obj->type != ACPI_TYPE_BUFFER) { + pr_err("invalid type : %d\n", obj->type); + return -EIO; + } + memcpy(buf, obj->buffer.pointer, input.length); + + return 0; +} + +#ifdef CONFIG_DCDBAS +static void run_smi_smbios_call(struct calling_interface_buffer *buf) { struct smi_cmd command; @@ -85,12 +125,28 @@ void dell_smbios_send_request(int class, int select) command.command_code = da_command_code; command.ebx = virt_to_phys(buffer); command.ecx = 0x42534931; - - buffer->class = class; - buffer->select = select; - dcdbas_smi_request(&command); } +#else +static void run_smi_smbios_call(struct calling_interface_buffer *buf) {} +#endif /* CONFIG_DCDBAS */ + +void dell_smbios_send_request(int class, int select) +{ + if (wmi_dev) { + struct wmi_calling_interface_buffer *buf = buffer; + + buf->smi.class = class; + buf->smi.select = select; + run_wmi_smbios_call(buf); + } else { + struct calling_interface_buffer *buf = buffer; + + buf->class = class; + buf->select = select; + run_smi_smbios_call(buf); + } +} EXPORT_SYMBOL_GPL(dell_smbios_send_request); struct calling_interface_token *dell_smbios_find_token(int tokenid) @@ -170,10 +226,43 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy) } } -static int __init dell_smbios_init(void) +static int dell_smbios_wmi_probe(struct wmi_device *wdev) +{ + /* no longer need the SMI page */ + free_page((unsigned long)buffer); + + /* WMI buffer should be 32k */ + buffer = (void *)__get_free_pages(GFP_KERNEL, 3); + if (!buffer) + return -ENOMEM; + bufferlen = sizeof(struct wmi_calling_interface_buffer); + wmi_dev = wdev; + return 0; +} + +static int dell_smbios_wmi_remove(struct wmi_device *wdev) { - int ret; + wmi_dev = NULL; + free_pages((unsigned long)buffer, 3); + return 0; +} +static const struct wmi_device_id dell_smbios_wmi_id_table[] = { + { .guid_string = DELL_WMI_SMBIOS_GUID }, + { }, +}; + +static struct wmi_driver dell_wmi_smbios_driver = { + .driver = { + .name = "dell-smbios", + }, + .probe = dell_smbios_wmi_probe, + .remove = dell_smbios_wmi_remove, + .id_table = dell_smbios_wmi_id_table, +}; + +static int __init dell_smbios_init(void) +{ dmi_walk(find_tokens, NULL); if (!da_tokens) { @@ -181,34 +270,39 @@ static int __init dell_smbios_init(void) return -ENODEV; } +#ifdef CONFIG_DCDBAS /* * Allocate buffer below 4GB for SMI data--only 32-bit physical addr * is passed to SMI handler. */ buffer = (void *)__get_free_page(GFP_KERNEL | GFP_DMA32); + bufferlen = sizeof(struct calling_interface_buffer); +#else + buffer = NULL; +#endif /* CONFIG_DCDBAS */ + wmi_driver_register(&dell_wmi_smbios_driver); + if (!buffer) { - ret = -ENOMEM; - goto fail_buffer; + kfree(da_tokens); + return -ENOMEM; } - return 0; - -fail_buffer: - kfree(da_tokens); - return ret; } static void __exit dell_smbios_exit(void) { kfree(da_tokens); free_page((unsigned long)buffer); + wmi_driver_unregister(&dell_wmi_smbios_driver); } subsys_initcall(dell_smbios_init); module_exit(dell_smbios_exit); + MODULE_AUTHOR("Matthew Garrett "); MODULE_AUTHOR("Gabriele Mazzotta "); MODULE_AUTHOR("Pali Rohár "); +MODULE_AUTHOR("Mario Limonciello "); MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS"); MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h index 45cbc2292cd3..2f6fce81ee69 100644 --- a/drivers/platform/x86/dell-smbios.h +++ b/drivers/platform/x86/dell-smbios.h @@ -4,6 +4,7 @@ * Copyright (c) Red Hat * Copyright (c) 2014 Gabriele Mazzotta * Copyright (c) 2014 Pali Rohár + * Copyright (c) 2017 Dell Inc. * * Based on documentation in the libsmbios package: * Copyright (C) 2005-2014 Dell Inc. @@ -18,9 +19,10 @@ struct notifier_block; -/* This structure will be modified by the firmware when we enter - * system management mode, hence the volatiles */ - +/* If called through fallback SMI rather than WMI this structure will be + * modified by the firmware when we enter system management mode, hence the + * volatiles + */ struct calling_interface_buffer { u16 class; u16 select; @@ -28,6 +30,13 @@ struct calling_interface_buffer { volatile u32 output[4]; } __packed; +struct wmi_calling_interface_buffer { + struct calling_interface_buffer smi; + u32 argattrib; + u32 blength; + u8 data[32724]; +} __packed; + struct calling_interface_token { u16 tokenID; u16 location;