From patchwork Sat May 27 05:31:18 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Darren Hart X-Patchwork-Id: 9751579 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 D6E186032C for ; Sat, 27 May 2017 05:36:19 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C9AA7283C5 for ; Sat, 27 May 2017 05:36:19 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BEA862846A; Sat, 27 May 2017 05:36:19 +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 504A3283C5 for ; Sat, 27 May 2017 05:36:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752149AbdE0FcD (ORCPT ); Sat, 27 May 2017 01:32:03 -0400 Received: from bombadil.infradead.org ([65.50.211.133]:57077 "EHLO bombadil.infradead.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752112AbdE0Fbp (ORCPT ); Sat, 27 May 2017 01:31:45 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20170209; h=Content-Transfer-Encoding: Content-Type:MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc: To:From:Sender:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id: List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=mgw+QWPgeKA7skT8DIzGJjRh15uMSYDvVYZoWD2JZwE=; b=hPldublGDl2pnVU0ayJYIjCCD n3NCp9uVzGF2+epR1vpffh1sl4Jg1Kys55X7Fm+Ay0w9MQcFH0bZZQJ0JfwhNcEKZFdBKtzWEe4Kw 9yLSy9sN7Ok5puy/jCYYuav/5ljbOll2pmd+3OiKheP5KB+OGU4e4nz/zQS75ADRb6MkdNzIMGk8e Tci7sYSXqIKDbF/bEaB2X7/dOL6Y9898p6HeVG9Tww9VbV3ylQA11gIXLYiLPwX2fdPcNCzRzuBI4 V43/KgUqIEpcD6ayEt24lrHl70Omcg159XckH9/8ZdYcwHq65T2iDlZdG2YX9xtjCA8wUFuxTYgZR Up+/V7o8w==; Received: from dvhart by bombadil.infradead.org with local (Exim 4.87 #1 (Red Hat Linux)) id 1dEUKG-0000eI-Nh; Sat, 27 May 2017 05:31:44 +0000 From: Darren Hart To: platform-driver-x86@vger.kernel.org Cc: Andy Shevchenko , Andy Lutomirski , Andy Lutomirski , Mario Limonciello , =?UTF-8?q?Pali=20Roh=C3=A1r?= , Rafael Wysocki , linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org, Darren Hart Subject: [PATCH 04/16] platform/x86: wmi: Track wmi devices per ACPI device Date: Fri, 26 May 2017 22:31:18 -0700 Message-Id: X-Mailer: git-send-email 2.9.4 In-Reply-To: References: In-Reply-To: References: MIME-Version: 1.0 Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Andy Lutomirski Currently we free all devices when we detach from any ACPI node. Instead, keep track of which node WMI devices are attached to and free them only as needed. While we are at it, match up notifications with the device they came from correctly. This will make our behavior more straightforward on systems with more than one WMI node in the ACPI tables (e.g. the Dell XPS 13 9350). This also adds a warning when GUIDs are not unique. NB: The guid_string parameter in guid_already_parsed was a little-endian binary GUID, not a string. Signed-off-by: Andy Lutomirski Cc: Andy Lutomirski Cc: Mario Limonciello Cc: Pali Rohár Cc: Rafael Wysocki Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/wmi.c | 58 ++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index ac60a51..faaa9a7 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -64,7 +64,7 @@ struct guid_block { struct wmi_block { struct list_head list; struct guid_block gblock; - acpi_handle handle; + struct acpi_device *acpi_device; wmi_notify_handler handler; void *handler_data; struct device dev; @@ -147,7 +147,7 @@ static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable) acpi_handle handle; block = &wblock->gblock; - handle = wblock->handle; + handle = wblock->acpi_device->handle; snprintf(method, 5, "WE%02X", block->notify_id); status = acpi_execute_simple_method(handle, method, enable); @@ -186,7 +186,7 @@ u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out) return AE_ERROR; block = &wblock->gblock; - handle = wblock->handle; + handle = wblock->acpi_device->handle; if (!(block->flags & ACPI_WMI_METHOD)) return AE_BAD_DATA; @@ -248,7 +248,7 @@ struct acpi_buffer *out) return AE_ERROR; block = &wblock->gblock; - handle = wblock->handle; + handle = wblock->acpi_device->handle; if (block->instance_count < instance) return AE_BAD_PARAMETER; @@ -321,7 +321,7 @@ const struct acpi_buffer *in) return AE_ERROR; block = &wblock->gblock; - handle = wblock->handle; + handle = wblock->acpi_device->handle; if (block->instance_count < instance) return AE_BAD_PARAMETER; @@ -525,8 +525,8 @@ acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out) if ((gblock->flags & ACPI_WMI_EVENT) && (gblock->notify_id == event)) - return acpi_evaluate_object(wblock->handle, "_WED", - &input, out); + return acpi_evaluate_object(wblock->acpi_device->handle, + "_WED", &input, out); } return AE_NOT_FOUND; @@ -618,27 +618,40 @@ static int wmi_create_device(const struct guid_block *gblock, return device_register(&wblock->dev); } -static void wmi_free_devices(void) +static void wmi_free_devices(struct acpi_device *device) { struct wmi_block *wblock, *next; /* Delete devices for all the GUIDs */ list_for_each_entry_safe(wblock, next, &wmi_block_list, list) { - list_del(&wblock->list); - if (wblock->dev.class) - device_unregister(&wblock->dev); - else - kfree(wblock); + if (wblock->acpi_device == device) { + list_del(&wblock->list); + if (wblock->dev.class) + device_unregister(&wblock->dev); + else + kfree(wblock); + } } } -static bool guid_already_parsed(const char *guid_string) +static bool guid_already_parsed(struct acpi_device *device, + const u8 *guid) { struct wmi_block *wblock; - list_for_each_entry(wblock, &wmi_block_list, list) - if (memcmp(wblock->gblock.guid, guid_string, 16) == 0) + list_for_each_entry(wblock, &wmi_block_list, list) { + if (memcmp(wblock->gblock.guid, guid, 16) == 0) { + /* + * Because we historically didn't track the relationship + * between GUIDs and ACPI nodes, we don't know whether + * we need to suppress GUIDs that are unique on a + * given node but duplicated across nodes. + */ + dev_warn(&device->dev, "duplicate WMI GUID %pUL (first instance was on %s)\n", + guid, dev_name(&wblock->acpi_device->dev)); return true; + } + } return false; } @@ -680,7 +693,7 @@ static int parse_wdg(struct acpi_device *device) if (!wblock) return -ENOMEM; - wblock->handle = device->handle; + wblock->acpi_device = device; wblock->gblock = gblock[i]; /* @@ -689,10 +702,10 @@ static int parse_wdg(struct acpi_device *device) case yet, so for now, we'll just ignore the duplicate for device creation. */ - if (!guid_already_parsed(gblock[i].guid)) { + if (!guid_already_parsed(device, gblock[i].guid)) { retval = wmi_create_device(&gblock[i], wblock, device); if (retval) { - wmi_free_devices(); + wmi_free_devices(device); goto out_free_pointer; } } @@ -767,8 +780,9 @@ static void acpi_wmi_notify(struct acpi_device *device, u32 event) wblock = list_entry(p, struct wmi_block, list); block = &wblock->gblock; - if ((block->flags & ACPI_WMI_EVENT) && - (block->notify_id == event)) { + if (wblock->acpi_device == device && + (block->flags & ACPI_WMI_EVENT) && + (block->notify_id == event)) { if (wblock->handler) wblock->handler(event, wblock->handler_data); if (debug_event) { @@ -788,7 +802,7 @@ static int acpi_wmi_remove(struct acpi_device *device) { acpi_remove_address_space_handler(device->handle, ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); - wmi_free_devices(); + wmi_free_devices(device); return 0; }