From 3bc3dc166dd23404bb2091292cd4e17f87678ca6 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Sun, 3 Aug 2025 21:18:11 +0200 Subject: [PATCH 01/10] ACPI: PM: Add power resource init function This way DMI based quirk matching and quirk flag initialization can be done just once - in the newly introduced acpi_power_resources_init() function, which is similar to existing acpi_*_init() functions. Convert the single already existing DMI match-based quirk in this ACPI power resource handler ("leave unused power resources on" quirk) to such one-time initialization in acpi_power_resources_init() function instead of re-running that DMI match each time acpi_turn_off_unused_power_resources() gets called. Signed-off-by: Maciej S. Szmigiero Link: https://patch.msgid.link/b173a6987f0b35597fd82400cb28f289786e03d0.1754243159.git.mail@maciej.szmigiero.name Signed-off-by: Rafael J. Wysocki --- drivers/acpi/internal.h | 1 + drivers/acpi/power.c | 10 +++++++++- drivers/acpi/scan.c | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index e2781864fdce..63354972ab0b 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -140,6 +140,7 @@ int __acpi_device_uevent_modalias(const struct acpi_device *adev, /* -------------------------------------------------------------------------- Power Resource -------------------------------------------------------------------------- */ +void acpi_power_resources_init(void); void acpi_power_resources_list_free(struct list_head *list); int acpi_extract_power_resources(union acpi_object *package, unsigned int start, struct list_head *list); diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index b7243d7563b1..cd9380b1f951 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -63,6 +63,8 @@ struct acpi_power_resource_entry { struct acpi_power_resource *resource; }; +static bool unused_power_resources_quirk; + static LIST_HEAD(acpi_power_resource_list); static DEFINE_MUTEX(power_resource_list_lock); @@ -1046,7 +1048,7 @@ void acpi_turn_off_unused_power_resources(void) { struct acpi_power_resource *resource; - if (dmi_check_system(dmi_leave_unused_power_resources_on)) + if (unused_power_resources_quirk) return; mutex_lock(&power_resource_list_lock); @@ -1065,3 +1067,9 @@ void acpi_turn_off_unused_power_resources(void) mutex_unlock(&power_resource_list_lock); } + +void __init acpi_power_resources_init(void) +{ + unused_power_resources_quirk = + dmi_check_system(dmi_leave_unused_power_resources_on); +} diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index fb1fe9f3b1a3..bb74e7834435 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2702,6 +2702,7 @@ void __init acpi_scan_init(void) acpi_memory_hotplug_init(); acpi_watchdog_init(); acpi_pnp_init(); + acpi_power_resources_init(); acpi_int340x_thermal_init(); acpi_init_lpit(); From 0467ed880a17c276c52e442c2454c7c16973a902 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Sun, 3 Aug 2025 21:18:12 +0200 Subject: [PATCH 02/10] ACPI: PM: Add HP EliteBook 855 G7 WWAN modem power resource quirk This laptop (and possibly similar models too) has power resource called "GP12.PXP_" for its Intel XMM7360 WWAN modem. For this power resource to turn ON power for the modem it needs certain internal flag called "ONEN" to be set: Method (_ON, 0, NotSerialized) // _ON_: Power On { If (^^^LPCB.EC0.ECRG) { If ((ONEN == Zero)) { Return (Zero) } (..) } } This flag only gets set from this power resource _OFF method, while the actual modem power gets turned off during suspend by "GP12.PTS" method called from the global _PTS (Prepare To Sleep) method. In fact, this power resource _OFF method implementation just sets the aforementioned flag: Method (_OFF, 0, NotSerialized) // _OFF: Power Off { OFEN = Zero ONEN = One } Upon hibernation finish, the kernel tries to set this power resource back ON since its _STA method returns 0 and the resource is still considered in use as it is declared as required for D0 for both the modem ACPI device (GP12.PWAN) and its parent PCIe port ACPI device object (GP12). But the _ON method won't do anything since that "ONEN" flag is not set. Overall, this means the modem is dead after hibernation finish until the laptop is rebooted since the modem power has been cut by _PTS and its PCI configuration was lost and not able to be restored. The easiest way to workaround this issue is to call this power resource _OFF method before calling the _ON method to make sure the "ONEN" flag gets properly set. This makes the modem alive once again after hibernation finish - with properly restored PCI configuration space. Since this platform does *not* support S3 the fact that acpi_resume_power_resources() is also called during resume from S3 is not a problem there. Do the DMI based quirk matching and quirk flag initialization just once - in acpi_power_resources_init() function. This way the whole resume path overhead of this change on other systems amounts to simple hp_eb_gp12pxp_quirk flag comparison. Signed-off-by: Maciej S. Szmigiero Link: https://patch.msgid.link/c6ff6931c5d27592052f30339de1b9cc298c43f0.1754243159.git.mail@maciej.szmigiero.name [ rjw: Changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/power.c | 80 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index cd9380b1f951..361a7721a6a8 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -23,6 +23,7 @@ #define pr_fmt(fmt) "ACPI: PM: " fmt +#include #include #include #include @@ -63,6 +64,7 @@ struct acpi_power_resource_entry { struct acpi_power_resource *resource; }; +static bool hp_eb_gp12pxp_quirk; static bool unused_power_resources_quirk; static LIST_HEAD(acpi_power_resource_list); @@ -994,6 +996,38 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle) } #ifdef CONFIG_ACPI_SLEEP +static bool resource_is_gp12pxp(acpi_handle handle) +{ + const char *path; + bool ret; + + path = acpi_handle_path(handle); + ret = path && strcmp(path, "\\_SB_.PCI0.GP12.PXP_") == 0; + kfree(path); + + return ret; +} + +static void acpi_resume_on_eb_gp12pxp(struct acpi_power_resource *resource) +{ + acpi_handle_notice(resource->device.handle, + "HP EB quirk - turning OFF then ON\n"); + + __acpi_power_off(resource); + __acpi_power_on(resource); + + /* + * Use the same delay as DSDT uses in modem _RST method. + * + * Otherwise we get "Unable to change power state from unknown to D0, + * device inaccessible" error for the modem PCI device after thaw. + * + * This power resource is normally being enabled only during thaw (once) + * so this wait is not a performance issue. + */ + msleep(200); +} + void acpi_resume_power_resources(void) { struct acpi_power_resource *resource; @@ -1015,8 +1049,14 @@ void acpi_resume_power_resources(void) if (state == ACPI_POWER_RESOURCE_STATE_OFF && resource->ref_count) { - acpi_handle_debug(resource->device.handle, "Turning ON\n"); - __acpi_power_on(resource); + if (hp_eb_gp12pxp_quirk && + resource_is_gp12pxp(resource->device.handle)) { + acpi_resume_on_eb_gp12pxp(resource); + } else { + acpi_handle_debug(resource->device.handle, + "Turning ON\n"); + __acpi_power_on(resource); + } } mutex_unlock(&resource->resource_lock); @@ -1026,6 +1066,41 @@ void acpi_resume_power_resources(void) } #endif +static const struct dmi_system_id dmi_hp_elitebook_gp12pxp_quirk[] = { +/* + * This laptop (and possibly similar models too) has power resource called + * "GP12.PXP_" for its WWAN modem. + * + * For this power resource to turn ON power for the modem it needs certain + * internal flag called "ONEN" to be set. + * This flag only gets set from this power resource "_OFF" method, while the + * actual modem power gets turned off during suspend by "GP12.PTS" method + * called from the global "_PTS" (Prepare To Sleep) method. + * On the other hand, this power resource "_OFF" method implementation just + * sets the aforementioned flag without actually doing anything else (it + * doesn't contain any code to actually turn off power). + * + * The above means that when upon hibernation finish we try to set this + * power resource back ON since its "_STA" method returns 0 (while the resource + * is still considered in use) its "_ON" method won't do anything since + * that "ONEN" flag is not set. + * Overall, this means the modem is dead until laptop is rebooted since its + * power has been cut by "_PTS" and its PCI configuration was lost and not able + * to be restored. + * + * The easiest way to workaround the issue is to call this power resource + * "_OFF" method before calling the "_ON" method to make sure the "ONEN" + * flag gets properly set. + */ + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 855 G7 Notebook PC"), + }, + }, + {} +}; + static const struct dmi_system_id dmi_leave_unused_power_resources_on[] = { { /* @@ -1070,6 +1145,7 @@ void acpi_turn_off_unused_power_resources(void) void __init acpi_power_resources_init(void) { + hp_eb_gp12pxp_quirk = dmi_check_system(dmi_hp_elitebook_gp12pxp_quirk); unused_power_resources_quirk = dmi_check_system(dmi_leave_unused_power_resources_on); } From 3a351de0d9c86e23b9eca25838b19468aab02f38 Mon Sep 17 00:00:00 2001 From: Sam van Kampen Date: Fri, 29 Aug 2025 14:52:22 +0000 Subject: [PATCH 03/10] ACPI: resource: Skip IRQ override on ASUS Vivobook Pro N6506CU Just like the other Vivobooks here, the N6506CU has its keyboard IRQ described as ActiveLow in the DSDT, which the kernel overrides to EdgeHigh, causing the internal keyboard not to work. Add the N6506CU to the irq1_level_low_skip_override[] quirk table to fix this. Signed-off-by: Sam van Kampen Link: https://patch.msgid.link/20250829145221.2294784-2-sam@tehsvk.net Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index b1ab192d7a08..ddedb6956a0d 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -510,6 +510,13 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = { DMI_MATCH(DMI_BOARD_NAME, "N6506M"), }, }, + { + /* Asus Vivobook Pro N6506CU* */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_BOARD_NAME, "N6506CU"), + }, + }, { /* LG Electronics 17U70P */ .matches = { From bf4206d7ac278bbd1eb2cf02d25486c2cc61b298 Mon Sep 17 00:00:00 2001 From: Chen Pei Date: Wed, 10 Sep 2025 17:41:36 +0800 Subject: [PATCH 04/10] ACPI: SPCR: Add support for DBG2 RISC-V SBI port subtype Commit 4aca2bef90bd1296 ("ACPICA: Headers: Add RISC-V SBI Subtype to DBG2") added the definition of ACPI_DBG2_RISCV_SBI_CON. Continue to implement its function so that the parameters of UART can be configured correctly. Subsequent calls to setup_earlycon() will reuse the earlycon based on SBI. Signed-off-by: Chen Pei Reviewed-by: Guo Ren (Alibaba Damo Academy) Link: https://patch.msgid.link/20250910094136.4423-1-cp0613@linux.alibaba.com [ rjw: Changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/spcr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c index cd36a97b0ea2..208d6bbc65e0 100644 --- a/drivers/acpi/spcr.c +++ b/drivers/acpi/spcr.c @@ -141,6 +141,9 @@ int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console) case ACPI_DBG2_16550_NVIDIA: uart = "uart"; break; + case ACPI_DBG2_RISCV_SBI_CON: + uart = "sbi"; + break; default: err = -ENOENT; goto done; From d0759b10989c5c5aae3d455458c9fc4e8cc694f7 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 15 Sep 2025 20:21:33 +0200 Subject: [PATCH 05/10] ACPI: property: Fix buffer properties extraction for subnodes The ACPI handle passed to acpi_extract_properties() as the first argument represents the ACPI namespace scope in which to look for objects returning buffers associated with buffer properties. For _DSD objects located immediately under ACPI devices, this handle is the same as the handle of the device object holding the _DSD, but for data-only subnodes it is not so. First of all, data-only subnodes are represented by objects that cannot hold other objects in their scopes (like control methods). Therefore a data-only subnode handle cannot be used for completing relative pathname segments, so the current code in in acpi_nondev_subnode_extract() passing a data-only subnode handle to acpi_extract_properties() is invalid. Moreover, a data-only subnode of device A may be represented by an object located in the scope of device B (which kind of makes sense, for instance, if A is a B's child). In that case, the scope in question would be the one of device B. In other words, the scope mentioned above is the same as the scope used for subnode object lookup in acpi_nondev_subnode_extract(). Accordingly, rearrange that function to use the same scope for the extraction of properties and subnode object lookup. Fixes: 103e10c69c61 ("ACPI: property: Add support for parsing buffer property UUID") Cc: 6.0+ # 6.0+ Signed-off-by: Rafael J. Wysocki Reviewed-by: Sakari Ailus Tested-by: Sakari Ailus --- drivers/acpi/property.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 436019d96027..83b03dce576c 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -83,6 +83,7 @@ static bool acpi_nondev_subnode_extract(union acpi_object *desc, struct fwnode_handle *parent) { struct acpi_data_node *dn; + acpi_handle scope = NULL; bool result; if (acpi_graph_ignore_port(handle)) @@ -98,27 +99,18 @@ static bool acpi_nondev_subnode_extract(union acpi_object *desc, INIT_LIST_HEAD(&dn->data.properties); INIT_LIST_HEAD(&dn->data.subnodes); - result = acpi_extract_properties(handle, desc, &dn->data); + /* + * The scope for the completion of relative pathname segments and + * subnode object lookup is the one of the namespace node (device) + * containing the object that has returned the package. That is, it's + * the scope of that object's parent device. + */ + if (handle) + acpi_get_parent(handle, &scope); - if (handle) { - acpi_handle scope; - acpi_status status; - - /* - * The scope for the subnode object lookup is the one of the - * namespace node (device) containing the object that has - * returned the package. That is, it's the scope of that - * object's parent. - */ - status = acpi_get_parent(handle, &scope); - if (ACPI_SUCCESS(status) - && acpi_enumerate_nondev_subnodes(scope, desc, &dn->data, - &dn->fwnode)) - result = true; - } else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data, - &dn->fwnode)) { + result = acpi_extract_properties(scope, desc, &dn->data); + if (acpi_enumerate_nondev_subnodes(scope, desc, &dn->data, &dn->fwnode)) result = true; - } if (result) { dn->handle = handle; From d06118fe9b03426484980ed4c189a8c7b99fa631 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 15 Sep 2025 20:23:28 +0200 Subject: [PATCH 06/10] ACPI: property: Disregard references in data-only subnode lists Data-only subnode links following the ACPI data subnode GUID in a _DSD package are expected to point to named objects returning _DSD-equivalent packages. If a reference to such an object is used in the target field of any of those links, that object will be evaluated in place (as a named object) and its return data will be embedded in the outer _DSD package. For this reason, it is not expected to see a subnode link with the target field containing a local reference (that would mean pointing to a device or another object that cannot be evaluated in place and therefore cannot return a _DSD-equivalent package). Accordingly, simplify the code parsing data-only subnode links to simply print a message when it encounters a local reference in the target field of one of those links. Moreover, since acpi_nondev_subnode_data_ok() would only have one caller after the change above, fold it into that caller. Link: https://lore.kernel.org/linux-acpi/CAJZ5v0jVeSrDO6hrZhKgRZrH=FpGD4vNUjFD8hV9WwN9TLHjzQ@mail.gmail.com/ Signed-off-by: Rafael J. Wysocki Reviewed-by: Sakari Ailus Tested-by: Sakari Ailus --- drivers/acpi/property.c | 53 ++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 83b03dce576c..5b7c10a2824d 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -124,14 +124,23 @@ static bool acpi_nondev_subnode_extract(union acpi_object *desc, return false; } -static bool acpi_nondev_subnode_data_ok(acpi_handle handle, - const union acpi_object *link, - struct list_head *list, - struct fwnode_handle *parent) +static bool acpi_nondev_subnode_ok(acpi_handle scope, + const union acpi_object *link, + struct list_head *list, + struct fwnode_handle *parent) { struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; + acpi_handle handle; acpi_status status; + if (!scope) + return false; + + status = acpi_get_handle(scope, link->package.elements[1].string.pointer, + &handle); + if (ACPI_FAILURE(status)) + return false; + status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf, ACPI_TYPE_PACKAGE); if (ACPI_FAILURE(status)) @@ -145,25 +154,6 @@ static bool acpi_nondev_subnode_data_ok(acpi_handle handle, return false; } -static bool acpi_nondev_subnode_ok(acpi_handle scope, - const union acpi_object *link, - struct list_head *list, - struct fwnode_handle *parent) -{ - acpi_handle handle; - acpi_status status; - - if (!scope) - return false; - - status = acpi_get_handle(scope, link->package.elements[1].string.pointer, - &handle); - if (ACPI_FAILURE(status)) - return false; - - return acpi_nondev_subnode_data_ok(handle, link, list, parent); -} - static bool acpi_add_nondev_subnodes(acpi_handle scope, union acpi_object *links, struct list_head *list, @@ -174,7 +164,6 @@ static bool acpi_add_nondev_subnodes(acpi_handle scope, for (i = 0; i < links->package.count; i++) { union acpi_object *link, *desc; - acpi_handle handle; bool result; link = &links->package.elements[i]; @@ -186,22 +175,26 @@ static bool acpi_add_nondev_subnodes(acpi_handle scope, if (link->package.elements[0].type != ACPI_TYPE_STRING) continue; - /* The second one may be a string, a reference or a package. */ + /* The second one may be a string or a package. */ switch (link->package.elements[1].type) { case ACPI_TYPE_STRING: result = acpi_nondev_subnode_ok(scope, link, list, parent); break; - case ACPI_TYPE_LOCAL_REFERENCE: - handle = link->package.elements[1].reference.handle; - result = acpi_nondev_subnode_data_ok(handle, link, list, - parent); - break; case ACPI_TYPE_PACKAGE: desc = &link->package.elements[1]; result = acpi_nondev_subnode_extract(desc, NULL, link, list, parent); break; + case ACPI_TYPE_LOCAL_REFERENCE: + /* + * It is not expected to see any local references in + * the links package because referencing a named object + * should cause it to be evaluated in place. + */ + acpi_handle_info(scope, "subnode %s: Unexpected reference\n", + link->package.elements[0].string.pointer); + fallthrough; default: result = false; break; From 737c3a09dcf69ba2814f3674947ccaec1861c985 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 15 Sep 2025 20:25:13 +0200 Subject: [PATCH 07/10] ACPI: property: Add code comments explaining what is going on In some places in the ACPI device properties handling code, it is unclear why the code is what it is. Some assumptions are not documented and some pieces of code are based on knowledge that is not mentioned anywhere. Add code comments explaining these things. Signed-off-by: Rafael J. Wysocki Reviewed-by: Sakari Ailus Tested-by: Sakari Ailus --- drivers/acpi/property.c | 46 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 5b7c10a2824d..f4776a4085e0 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -108,7 +108,18 @@ static bool acpi_nondev_subnode_extract(union acpi_object *desc, if (handle) acpi_get_parent(handle, &scope); + /* + * Extract properties from the _DSD-equivalent package pointed to by + * desc and use scope (if not NULL) for the completion of relative + * pathname segments. + * + * The extracted properties will be held in the new data node dn. + */ result = acpi_extract_properties(scope, desc, &dn->data); + /* + * Look for subnodes in the _DSD-equivalent package pointed to by desc + * and create child nodes of dn if there are any. + */ if (acpi_enumerate_nondev_subnodes(scope, desc, &dn->data, &dn->fwnode)) result = true; @@ -133,6 +144,12 @@ static bool acpi_nondev_subnode_ok(acpi_handle scope, acpi_handle handle; acpi_status status; + /* + * If the scope is unknown, the _DSD-equivalent package being parsed + * was embedded in an outer _DSD-equivalent package as a result of + * direct evaluation of an object pointed to by a reference. In that + * case, using a pathname as the target object pointer is invalid. + */ if (!scope) return false; @@ -162,6 +179,10 @@ static bool acpi_add_nondev_subnodes(acpi_handle scope, bool ret = false; int i; + /* + * Every element in the links package is expected to represent a link + * to a non-device node in a tree containing device-specific data. + */ for (i = 0; i < links->package.count; i++) { union acpi_object *link, *desc; bool result; @@ -171,17 +192,38 @@ static bool acpi_add_nondev_subnodes(acpi_handle scope, if (link->package.count != 2) continue; - /* The first one must be a string. */ + /* The first one (the key) must be a string. */ if (link->package.elements[0].type != ACPI_TYPE_STRING) continue; - /* The second one may be a string or a package. */ + /* The second one (the target) may be a string or a package. */ switch (link->package.elements[1].type) { case ACPI_TYPE_STRING: + /* + * The string is expected to be a full pathname or a + * pathname segment relative to the given scope. That + * pathname is expected to point to an object returning + * a package that contains _DSD-equivalent information. + */ result = acpi_nondev_subnode_ok(scope, link, list, parent); break; case ACPI_TYPE_PACKAGE: + /* + * This happens when a reference is used in AML to + * point to the target. Since the target is expected + * to be a named object, a reference to it will cause it + * to be avaluated in place and its return package will + * be embedded in the links package at the location of + * the reference. + * + * The target package is expected to contain _DSD- + * equivalent information, but the scope in which it + * is located in the original AML is unknown. Thus + * it cannot contain pathname segments represented as + * strings because there is no way to build full + * pathnames out of them. + */ desc = &link->package.elements[1]; result = acpi_nondev_subnode_extract(desc, NULL, link, list, parent); From baf60d5cb8bc6b85511c5df5f0ad7620bb66d23c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 15 Sep 2025 20:28:52 +0200 Subject: [PATCH 08/10] ACPI: property: Do not pass NULL handles to acpi_attach_data() In certain circumstances, the ACPI handle of a data-only node may be NULL, in which case it does not make sense to attempt to attach that node to an ACPI namespace object, so update the code to avoid attempts to do so. This prevents confusing and unuseful error messages from being printed. Also document the fact that the ACPI handle of a data-only node may be NULL and when that happens in a code comment. In addition, make acpi_add_nondev_subnodes() print a diagnostic message for each data-only node with an unknown ACPI namespace scope. Fixes: 1d52f10917a7 ("ACPI: property: Tie data nodes to acpi handles") Cc: 6.0+ # 6.0+ Signed-off-by: Rafael J. Wysocki Reviewed-by: Sakari Ailus Tested-by: Sakari Ailus --- drivers/acpi/property.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index f4776a4085e0..c086786fe84c 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -124,6 +124,10 @@ static bool acpi_nondev_subnode_extract(union acpi_object *desc, result = true; if (result) { + /* + * This will be NULL if the desc package is embedded in an outer + * _DSD-equivalent package and its scope cannot be determined. + */ dn->handle = handle; dn->data.pointer = desc; list_add_tail(&dn->sibling, list); @@ -224,6 +228,8 @@ static bool acpi_add_nondev_subnodes(acpi_handle scope, * strings because there is no way to build full * pathnames out of them. */ + acpi_handle_debug(scope, "subnode %s: Unknown scope\n", + link->package.elements[0].string.pointer); desc = &link->package.elements[1]; result = acpi_nondev_subnode_extract(desc, NULL, link, list, parent); @@ -396,6 +402,9 @@ static void acpi_untie_nondev_subnodes(struct acpi_device_data *data) struct acpi_data_node *dn; list_for_each_entry(dn, &data->subnodes, sibling) { + if (!dn->handle) + continue; + acpi_detach_data(dn->handle, acpi_nondev_subnode_tag); acpi_untie_nondev_subnodes(&dn->data); @@ -410,6 +419,9 @@ static bool acpi_tie_nondev_subnodes(struct acpi_device_data *data) acpi_status status; bool ret; + if (!dn->handle) + continue; + status = acpi_attach_data(dn->handle, acpi_nondev_subnode_tag, dn); if (ACPI_FAILURE(status) && status != AE_ALREADY_EXISTS) { acpi_handle_err(dn->handle, "Can't tag data node\n"); From 0f83b1d436c98083dcbf7f3e6204015ed4a46743 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 15 Sep 2025 20:29:50 +0200 Subject: [PATCH 09/10] ACPI: property: Adjust failure handling in acpi_nondev_subnode_extract() Make acpi_nondev_subnode_extract() follow the usual code flow pattern in which failure is handled at the point where it is detected. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Reviewed-by: Sakari Ailus Tested-by: Sakari Ailus --- drivers/acpi/property.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index c086786fe84c..54baa23a9e5a 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -123,20 +123,21 @@ static bool acpi_nondev_subnode_extract(union acpi_object *desc, if (acpi_enumerate_nondev_subnodes(scope, desc, &dn->data, &dn->fwnode)) result = true; - if (result) { - /* - * This will be NULL if the desc package is embedded in an outer - * _DSD-equivalent package and its scope cannot be determined. - */ - dn->handle = handle; - dn->data.pointer = desc; - list_add_tail(&dn->sibling, list); - return true; + if (!result) { + kfree(dn); + acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n"); + return false; } - kfree(dn); - acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n"); - return false; + /* + * This will be NULL if the desc package is embedded in an outer + * _DSD-equivalent package and its scope cannot be determined. + */ + dn->handle = handle; + dn->data.pointer = desc; + list_add_tail(&dn->sibling, list); + + return true; } static bool acpi_nondev_subnode_ok(acpi_handle scope, From 4d330fe54145ecfbb657ac01a554fdedf3c1927e Mon Sep 17 00:00:00 2001 From: Chen Pei Date: Sat, 13 Sep 2025 15:08:15 +0800 Subject: [PATCH 10/10] ACPI: SPCR: Support Precise Baud Rate field The Microsoft Serial Port Console Redirection (SPCR) specification revision 1.09 comprises additional field: Precise Baud Rate [1]. It is used to describe non-traditional baud rates (such as those used by high-speed UARTs). It contains a specific non-zero baud rate which overrides the value of the Configured Baud Rate field. If this field is zero or not present, Configured Baud Rate is used. Link: https://learn.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table [1] Signed-off-by: Chen Pei Link: https://patch.msgid.link/20250913070815.16758-1-cp0613@linux.alibaba.com [ rjw: Corrected typo in the subject ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/spcr.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c index 208d6bbc65e0..d4d52d5e9016 100644 --- a/drivers/acpi/spcr.c +++ b/drivers/acpi/spcr.c @@ -149,7 +149,15 @@ int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console) goto done; } - switch (table->baud_rate) { + /* + * SPCR 1.09 defines Precise Baud Rate Filed contains a specific + * non-zero baud rate which overrides the value of the Configured + * Baud Rate field. If this field is zero or not present, Configured + * Baud Rate is used. + */ + if (table->precise_baudrate) + baud_rate = table->precise_baudrate; + else switch (table->baud_rate) { case 0: /* * SPCR 1.04 defines 0 as a preconfigured state of UART.