Skip to content

Commit 73f0f2b

Browse files
Wer-Wolfij-intel
authored andcommitted
platform/x86: wmi: Fix WMI device naming issue
When multiple WMI devices with the same GUID are present inside a given system, the WMI driver core might fail to register all of them. Consider the following scenario: WMI devices (<GUID>[-<ID>]): 05901221-D566-11D1-B2F0-00A0C9062910 (on PNP0C14:00) 05901221-D566-11D1-B2F0-00A0C9062910-1 (on PNP0C14:01) If the WMI core driver somehow unbinds from PNP0C14:00, the following will happen upon rebinding: 1. The WMI driver core counts all registered WMI devices with a GUID of 05901221-D566-11D1-B2F0-00A0C9062910 (count: 1). 2. The new WMI device will be named "05901221-D566-11D1-B2F0-00A0C9062910-1" because another device with the same GUID is already registered (on PNP0C14:01). 3. The new WMI device cannot be registered due to a name conflict. Use a IDA when building the WMI device name to avoid such name collisions by ensuring that a given WMI device ID is not reused. Userspace applications using udev for WMI device detection are not impacted by this change. Additionally userspace applications that do fully support the existing naming scheme are also not impacted. Only userspace applications using hardcoded sysfs paths will break. Introduce a kconfig option for restoring the old naming scheme to give developers time to fix any compatibility issues. Tested on a Asus Prime B650-Plus. Signed-off-by: Armin Wolf <W_Armin@gmx.de> Link: https://lore.kernel.org/r/20250610055526.23688-2-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
1 parent c9de2e5 commit 73f0f2b

File tree

2 files changed

+41
-5
lines changed

2 files changed

+41
-5
lines changed

drivers/platform/x86/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,15 @@ config ACPI_WMI
3737
It is safe to enable this driver even if your DSDT doesn't define
3838
any ACPI-WMI devices.
3939

40+
config ACPI_WMI_LEGACY_DEVICE_NAMES
41+
bool "Use legacy WMI device naming scheme"
42+
depends on ACPI_WMI
43+
help
44+
Say Y here to force the WMI driver core to use the old WMI device naming
45+
scheme when creating WMI devices. Doing so might be necessary for some
46+
userspace applications but will cause the registration of WMI devices with
47+
the same GUID to fail in some corner cases.
48+
4049
config WMI_BMOF
4150
tristate "WMI embedded Binary MOF driver"
4251
depends on ACPI_WMI

drivers/platform/x86/wmi.c

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/bits.h>
2121
#include <linux/build_bug.h>
2222
#include <linux/device.h>
23+
#include <linux/idr.h>
2324
#include <linux/init.h>
2425
#include <linux/kernel.h>
2526
#include <linux/module.h>
@@ -74,6 +75,8 @@ struct wmi_guid_count_context {
7475
int count;
7576
};
7677

78+
static DEFINE_IDA(wmi_ida);
79+
7780
/*
7881
* If the GUID data block is marked as expensive, we must enable and
7982
* explicitily disable data collection.
@@ -978,6 +981,19 @@ static int guid_count(const guid_t *guid)
978981
return context.count;
979982
}
980983

984+
static int wmi_dev_set_name(struct wmi_block *wblock, int count)
985+
{
986+
if (IS_ENABLED(CONFIG_ACPI_WMI_LEGACY_DEVICE_NAMES)) {
987+
if (count)
988+
return dev_set_name(&wblock->dev.dev, "%pUL-%d", &wblock->gblock.guid,
989+
count);
990+
else
991+
return dev_set_name(&wblock->dev.dev, "%pUL", &wblock->gblock.guid);
992+
}
993+
994+
return dev_set_name(&wblock->dev.dev, "%pUL-%d", &wblock->gblock.guid, wblock->dev.dev.id);
995+
}
996+
981997
static int wmi_create_device(struct device *wmi_bus_dev,
982998
struct wmi_block *wblock,
983999
struct acpi_device *device)
@@ -986,7 +1002,7 @@ static int wmi_create_device(struct device *wmi_bus_dev,
9861002
struct acpi_device_info *info;
9871003
acpi_handle method_handle;
9881004
acpi_status status;
989-
int count;
1005+
int count, ret;
9901006

9911007
if (wblock->gblock.flags & ACPI_WMI_EVENT) {
9921008
wblock->dev.dev.type = &wmi_type_event;
@@ -1057,11 +1073,18 @@ static int wmi_create_device(struct device *wmi_bus_dev,
10571073
if (count < 0)
10581074
return count;
10591075

1060-
if (count) {
1061-
dev_set_name(&wblock->dev.dev, "%pUL-%d", &wblock->gblock.guid, count);
1076+
if (count)
10621077
set_bit(WMI_GUID_DUPLICATED, &wblock->flags);
1063-
} else {
1064-
dev_set_name(&wblock->dev.dev, "%pUL", &wblock->gblock.guid);
1078+
1079+
ret = ida_alloc(&wmi_ida, GFP_KERNEL);
1080+
if (ret < 0)
1081+
return ret;
1082+
1083+
wblock->dev.dev.id = ret;
1084+
ret = wmi_dev_set_name(wblock, count);
1085+
if (ret < 0) {
1086+
ida_free(&wmi_ida, wblock->dev.dev.id);
1087+
return ret;
10651088
}
10661089

10671090
device_initialize(&wblock->dev.dev);
@@ -1147,6 +1170,7 @@ static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev)
11471170
dev_err(wmi_bus_dev, "failed to register %pUL\n",
11481171
&wblock->gblock.guid);
11491172

1173+
ida_free(&wmi_ida, wblock->dev.dev.id);
11501174
put_device(&wblock->dev.dev);
11511175
}
11521176
}
@@ -1246,7 +1270,10 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, void *context
12461270

12471271
static int wmi_remove_device(struct device *dev, void *data)
12481272
{
1273+
int id = dev->id;
1274+
12491275
device_unregister(dev);
1276+
ida_free(&wmi_ida, id);
12501277

12511278
return 0;
12521279
}

0 commit comments

Comments
 (0)