[PATCH 2/2] acpi: bus: Introduce acpi.skip_ids= boot parameter
[email protected] Wed, 12 Aug 2026 19:41:29 -0700
| Newsgroups | gmane.linux.acpi.devel,gmane.linux.kernel |
|---|---|
| Message-ID | <[email protected]> |
From: Denis Mukhin <[email protected]> In virtualized environments it is possible that a device managed by the hypervisor or another VM is described in the ACPI tables. In these cases, binding a device driver to it can cause functional issues. To resolve device ownership conflicts, skip enumeration of ACPI devices whose ACPI IDs match entries specified via a new boot-time parameter: acpi.skip_ids=<HID[:UID]>[,<HID[:UID]>...] This parameter may also be used when a single kernel image must support both bare-metal and virtualized environments - for example, when the image is shared across multiple VMs and only selected platform devices are exposed through passthrough. Note, a single driver may support multiple devices and only a subset of those devices may require exclusion (for example, ABCD0020:00 but not ABCD0020:01). As a result, existing 'initcall_blacklist=' is not an appropriate solution to resolve the ownership conflict. Add brief explanation for apci.skip_ids= in the kernel command line documentation. Signed-off-by: Denis Mukhin <[email protected]> --- .../admin-guide/kernel-parameters.txt | 5 ++ drivers/acpi/bus.c | 60 +++++++++++++++++-- 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 3d35270dddef..a2d4bd9e37b9 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -195,6 +195,11 @@ Kernel parameters ACPI firmware problems, as the system might behave erratically after having encountered a fatal ACPI error. + acpi.skip_ids= [ACPI] Skip enumeration of ACPI devices whose HID[:UID] + matches an entry in the given comma-separated list + (up to 16 entries). + Format: HID[:UID][,HID[:UID]...] + acpi_enforce_resources= [ACPI] { strict | lax | no } Check for resource conflicts between native drivers diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a30a904f6535..86dba970bfc2 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -38,6 +38,15 @@ struct acpi_device *acpi_root; struct proc_dir_entry *acpi_root_dir; EXPORT_SYMBOL(acpi_root_dir); +#define ACPI_MAX_SKIP_IDS 16 /* Arbitrary limit. */ + +static char *acpi_skip_ids[ACPI_MAX_SKIP_IDS]; +static int acpi_skip_num; +module_param_array_named(skip_ids, acpi_skip_ids, charp, + &acpi_skip_num, 0444); +MODULE_PARM_DESC(skip_ids, + "Skip binding ACPI drivers to devices with matching _HID[:_UID]"); + #ifdef CONFIG_X86 #ifdef CONFIG_ACPI_CUSTOM_DSDT static inline int set_copy_dsdt(const struct dmi_system_id *id) @@ -1008,6 +1017,9 @@ static bool __acpi_match_device(const struct acpi_device *device, { const struct acpi_device_id *id; struct acpi_hardware_id *hwid; + struct acpi_device_info *info = NULL; + bool ret = false; + int i; /* * If the device is not present, it is unnecessary to load device @@ -1016,8 +1028,42 @@ static bool __acpi_match_device(const struct acpi_device *device, if (!device || !device->status.present) return false; + if (acpi_skip_num) { + acpi_status status; + + status = acpi_get_object_info(device->handle, &info); + if (ACPI_FAILURE(status)) + info = NULL; + } + list_for_each_entry(hwid, &device->pnp.ids, list) { - /* First, check the ACPI/PNP IDs provided by the caller. */ + /* First, check whether device ACPI ID is in the skip list. */ + for (i = 0; i < acpi_skip_num; i++) { + char with_uid[MAX_ACPI_DEVICE_NAME_LEN]; + u32 uid; + + if (!strcasecmp(acpi_skip_ids[i], hwid->id)) { + ret = false; + goto out; + } + + if (!info || !(info->valid & ACPI_VALID_UID)) + continue; + + if (kstrtou32(info->unique_id.string, 0, &uid)) + snprintf(with_uid, sizeof(with_uid), "%s:%s", + hwid->id, info->unique_id.string); + else + snprintf(with_uid, sizeof(with_uid), "%s:%02x", + hwid->id, uid); + + if (!strcasecmp(acpi_skip_ids[i], with_uid)) { + ret = false; + goto out; + } + } + + /* Second, check the ACPI/PNP IDs provided by the caller. */ if (acpi_ids) { for (id = acpi_ids; id->id[0] || id->cls; id++) { if (id->id[0] && !strcmp((char *)id->id, hwid->id)) @@ -1031,12 +1077,18 @@ static bool __acpi_match_device(const struct acpi_device *device, * Next, check ACPI_DT_NAMESPACE_HID and try to match the * "compatible" property if found. */ - if (!strcmp(ACPI_DT_NAMESPACE_HID, hwid->id)) - return acpi_of_match_device(device, of_ids, of_id); + if (!strcmp(ACPI_DT_NAMESPACE_HID, hwid->id)) { + ret = acpi_of_match_device(device, of_ids, of_id); + goto out; + } } - return false; + +out: + kfree(info); + return ret; out_acpi_match: + kfree(info); if (acpi_id) *acpi_id = id; return true; -- 2.54.0