From patchwork Tue Dec 1 01:05:54 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Lutomirski X-Patchwork-Id: 7731451 Return-Path: X-Original-To: patchwork-platform-driver-x86@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id EF72D9F387 for ; Tue, 1 Dec 2015 01:06:22 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 1341D2066B for ; Tue, 1 Dec 2015 01:06:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0B72B20672 for ; Tue, 1 Dec 2015 01:06:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754955AbbLABGP (ORCPT ); Mon, 30 Nov 2015 20:06:15 -0500 Received: from mail.kernel.org ([198.145.29.136]:46672 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754793AbbLABGO (ORCPT ); Mon, 30 Nov 2015 20:06:14 -0500 Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 51D0F20664; Tue, 1 Dec 2015 01:06:13 +0000 (UTC) Received: from localhost (c-71-202-137-17.hsd1.ca.comcast.net [71.202.137.17]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 5EB9620665; Tue, 1 Dec 2015 01:06:12 +0000 (UTC) From: Andy Lutomirski To: Darren Hart Cc: Matthew Garrett , linux-acpi@vger.kernel.org, platform-driver-x86@vger.kernel.org, Mario Limonciello , =?UTF-8?q?Pali=20Roh=C3=A1r?= , Andy Lutomirski Subject: [PATCH 04/14] wmi: Track wmi devices per ACPI device Date: Mon, 30 Nov 2015 17:05:54 -0800 Message-Id: <1f46c6ccd05508b4fdf1537373df48d8b6c06e81.1448931782.git.luto@kernel.org> X-Mailer: git-send-email 2.5.0 In-Reply-To: References: In-Reply-To: References: X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 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're 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 aren't unique. NB: The guid_string parameter in guid_already_parsed was a little-endian binary GUID, not a string. Signed-off-by: Andy Lutomirski --- 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 fc1f339b7431..dcb34a5f5669 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -63,7 +63,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; @@ -225,7 +225,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); @@ -264,7 +264,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; @@ -326,7 +326,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; @@ -399,7 +399,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; @@ -603,8 +603,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; @@ -696,27 +696,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; } @@ -758,7 +771,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]; /* @@ -767,10 +780,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; } } @@ -845,8 +858,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) { @@ -866,7 +880,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; }