mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-08-31 06:09:56 +00:00
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>
This commit is contained in:
parent
c9de2e5c15
commit
73f0f2b52c
@ -37,6 +37,15 @@ config ACPI_WMI
|
||||
It is safe to enable this driver even if your DSDT doesn't define
|
||||
any ACPI-WMI devices.
|
||||
|
||||
config ACPI_WMI_LEGACY_DEVICE_NAMES
|
||||
bool "Use legacy WMI device naming scheme"
|
||||
depends on ACPI_WMI
|
||||
help
|
||||
Say Y here to force the WMI driver core to use the old WMI device naming
|
||||
scheme when creating WMI devices. Doing so might be necessary for some
|
||||
userspace applications but will cause the registration of WMI devices with
|
||||
the same GUID to fail in some corner cases.
|
||||
|
||||
config WMI_BMOF
|
||||
tristate "WMI embedded Binary MOF driver"
|
||||
depends on ACPI_WMI
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/bits.h>
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
@ -74,6 +75,8 @@ struct wmi_guid_count_context {
|
||||
int count;
|
||||
};
|
||||
|
||||
static DEFINE_IDA(wmi_ida);
|
||||
|
||||
/*
|
||||
* If the GUID data block is marked as expensive, we must enable and
|
||||
* explicitily disable data collection.
|
||||
@ -978,6 +981,19 @@ static int guid_count(const guid_t *guid)
|
||||
return context.count;
|
||||
}
|
||||
|
||||
static int wmi_dev_set_name(struct wmi_block *wblock, int count)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_ACPI_WMI_LEGACY_DEVICE_NAMES)) {
|
||||
if (count)
|
||||
return dev_set_name(&wblock->dev.dev, "%pUL-%d", &wblock->gblock.guid,
|
||||
count);
|
||||
else
|
||||
return dev_set_name(&wblock->dev.dev, "%pUL", &wblock->gblock.guid);
|
||||
}
|
||||
|
||||
return dev_set_name(&wblock->dev.dev, "%pUL-%d", &wblock->gblock.guid, wblock->dev.dev.id);
|
||||
}
|
||||
|
||||
static int wmi_create_device(struct device *wmi_bus_dev,
|
||||
struct wmi_block *wblock,
|
||||
struct acpi_device *device)
|
||||
@ -986,7 +1002,7 @@ static int wmi_create_device(struct device *wmi_bus_dev,
|
||||
struct acpi_device_info *info;
|
||||
acpi_handle method_handle;
|
||||
acpi_status status;
|
||||
int count;
|
||||
int count, ret;
|
||||
|
||||
if (wblock->gblock.flags & ACPI_WMI_EVENT) {
|
||||
wblock->dev.dev.type = &wmi_type_event;
|
||||
@ -1057,11 +1073,18 @@ static int wmi_create_device(struct device *wmi_bus_dev,
|
||||
if (count < 0)
|
||||
return count;
|
||||
|
||||
if (count) {
|
||||
dev_set_name(&wblock->dev.dev, "%pUL-%d", &wblock->gblock.guid, count);
|
||||
if (count)
|
||||
set_bit(WMI_GUID_DUPLICATED, &wblock->flags);
|
||||
} else {
|
||||
dev_set_name(&wblock->dev.dev, "%pUL", &wblock->gblock.guid);
|
||||
|
||||
ret = ida_alloc(&wmi_ida, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
wblock->dev.dev.id = ret;
|
||||
ret = wmi_dev_set_name(wblock, count);
|
||||
if (ret < 0) {
|
||||
ida_free(&wmi_ida, wblock->dev.dev.id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
device_initialize(&wblock->dev.dev);
|
||||
@ -1147,6 +1170,7 @@ static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev)
|
||||
dev_err(wmi_bus_dev, "failed to register %pUL\n",
|
||||
&wblock->gblock.guid);
|
||||
|
||||
ida_free(&wmi_ida, wblock->dev.dev.id);
|
||||
put_device(&wblock->dev.dev);
|
||||
}
|
||||
}
|
||||
@ -1246,7 +1270,10 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, void *context
|
||||
|
||||
static int wmi_remove_device(struct device *dev, void *data)
|
||||
{
|
||||
int id = dev->id;
|
||||
|
||||
device_unregister(dev);
|
||||
ida_free(&wmi_ida, id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user