Skip to content

Commit 6173176

Browse files
committed
Merge branches 'acpi-property', 'acpi-resource', 'acpi-pm' and 'acpi-tables'
Merge updates of the ACPI device properties management code, ACPI resources management code, ACPI power management, and ACPI data tables parsing code for 6.18-rc1: - Fix ACPI buffer properties extraction for data-only subnodes represented as _DSD-equivalent packages (Rafael Wysocki) - Fix handling of ACPI data-only subnodes represented as _DSD-equivalent packages in the case when they are embedded in larger _DSD-equivalent packages and clean up acpi_nondev_subnode_extract() (Rafael Wysocki) - Skip ACPI IRQ override on ASUS Vivobook Pro N6506CU (Sam van Kampen) - Add power resource init function and use it for introducing an HP EliteBook 855 G7 WWAN modem power resource quirk (Maciej Szmigiero) - Add support for DBG2 RISC-V SBI port subtype and Precise Baud Rate field to the ACPI SPCR table parser (Chen Pei) * acpi-property: ACPI: property: Adjust failure handling in acpi_nondev_subnode_extract() ACPI: property: Do not pass NULL handles to acpi_attach_data() ACPI: property: Add code comments explaining what is going on ACPI: property: Disregard references in data-only subnode lists ACPI: property: Fix buffer properties extraction for subnodes * acpi-resource: ACPI: resource: Skip IRQ override on ASUS Vivobook Pro N6506CU * acpi-pm: ACPI: PM: Add HP EliteBook 855 G7 WWAN modem power resource quirk ACPI: PM: Add power resource init function * acpi-tables: ACPI: SPCR: Support Precise Baud Rate field ACPI: SPCR: Add support for DBG2 RISC-V SBI port subtype
5 parents be61a77 + 0f83b1d + 3a351de + 0467ed8 + 4d330fe commit 6173176

File tree

6 files changed

+204
-60
lines changed

6 files changed

+204
-60
lines changed

drivers/acpi/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ int __acpi_device_uevent_modalias(const struct acpi_device *adev,
140140
/* --------------------------------------------------------------------------
141141
Power Resource
142142
-------------------------------------------------------------------------- */
143+
void acpi_power_resources_init(void);
143144
void acpi_power_resources_list_free(struct list_head *list);
144145
int acpi_extract_power_resources(union acpi_object *package, unsigned int start,
145146
struct list_head *list);

drivers/acpi/power.c

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
#define pr_fmt(fmt) "ACPI: PM: " fmt
2525

26+
#include <linux/delay.h>
2627
#include <linux/dmi.h>
2728
#include <linux/kernel.h>
2829
#include <linux/module.h>
@@ -63,6 +64,9 @@ struct acpi_power_resource_entry {
6364
struct acpi_power_resource *resource;
6465
};
6566

67+
static bool hp_eb_gp12pxp_quirk;
68+
static bool unused_power_resources_quirk;
69+
6670
static LIST_HEAD(acpi_power_resource_list);
6771
static DEFINE_MUTEX(power_resource_list_lock);
6872

@@ -992,6 +996,38 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle)
992996
}
993997

994998
#ifdef CONFIG_ACPI_SLEEP
999+
static bool resource_is_gp12pxp(acpi_handle handle)
1000+
{
1001+
const char *path;
1002+
bool ret;
1003+
1004+
path = acpi_handle_path(handle);
1005+
ret = path && strcmp(path, "\\_SB_.PCI0.GP12.PXP_") == 0;
1006+
kfree(path);
1007+
1008+
return ret;
1009+
}
1010+
1011+
static void acpi_resume_on_eb_gp12pxp(struct acpi_power_resource *resource)
1012+
{
1013+
acpi_handle_notice(resource->device.handle,
1014+
"HP EB quirk - turning OFF then ON\n");
1015+
1016+
__acpi_power_off(resource);
1017+
__acpi_power_on(resource);
1018+
1019+
/*
1020+
* Use the same delay as DSDT uses in modem _RST method.
1021+
*
1022+
* Otherwise we get "Unable to change power state from unknown to D0,
1023+
* device inaccessible" error for the modem PCI device after thaw.
1024+
*
1025+
* This power resource is normally being enabled only during thaw (once)
1026+
* so this wait is not a performance issue.
1027+
*/
1028+
msleep(200);
1029+
}
1030+
9951031
void acpi_resume_power_resources(void)
9961032
{
9971033
struct acpi_power_resource *resource;
@@ -1013,8 +1049,14 @@ void acpi_resume_power_resources(void)
10131049

10141050
if (state == ACPI_POWER_RESOURCE_STATE_OFF
10151051
&& resource->ref_count) {
1016-
acpi_handle_debug(resource->device.handle, "Turning ON\n");
1017-
__acpi_power_on(resource);
1052+
if (hp_eb_gp12pxp_quirk &&
1053+
resource_is_gp12pxp(resource->device.handle)) {
1054+
acpi_resume_on_eb_gp12pxp(resource);
1055+
} else {
1056+
acpi_handle_debug(resource->device.handle,
1057+
"Turning ON\n");
1058+
__acpi_power_on(resource);
1059+
}
10181060
}
10191061

10201062
mutex_unlock(&resource->resource_lock);
@@ -1024,6 +1066,41 @@ void acpi_resume_power_resources(void)
10241066
}
10251067
#endif
10261068

1069+
static const struct dmi_system_id dmi_hp_elitebook_gp12pxp_quirk[] = {
1070+
/*
1071+
* This laptop (and possibly similar models too) has power resource called
1072+
* "GP12.PXP_" for its WWAN modem.
1073+
*
1074+
* For this power resource to turn ON power for the modem it needs certain
1075+
* internal flag called "ONEN" to be set.
1076+
* This flag only gets set from this power resource "_OFF" method, while the
1077+
* actual modem power gets turned off during suspend by "GP12.PTS" method
1078+
* called from the global "_PTS" (Prepare To Sleep) method.
1079+
* On the other hand, this power resource "_OFF" method implementation just
1080+
* sets the aforementioned flag without actually doing anything else (it
1081+
* doesn't contain any code to actually turn off power).
1082+
*
1083+
* The above means that when upon hibernation finish we try to set this
1084+
* power resource back ON since its "_STA" method returns 0 (while the resource
1085+
* is still considered in use) its "_ON" method won't do anything since
1086+
* that "ONEN" flag is not set.
1087+
* Overall, this means the modem is dead until laptop is rebooted since its
1088+
* power has been cut by "_PTS" and its PCI configuration was lost and not able
1089+
* to be restored.
1090+
*
1091+
* The easiest way to workaround the issue is to call this power resource
1092+
* "_OFF" method before calling the "_ON" method to make sure the "ONEN"
1093+
* flag gets properly set.
1094+
*/
1095+
{
1096+
.matches = {
1097+
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
1098+
DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 855 G7 Notebook PC"),
1099+
},
1100+
},
1101+
{}
1102+
};
1103+
10271104
static const struct dmi_system_id dmi_leave_unused_power_resources_on[] = {
10281105
{
10291106
/*
@@ -1046,7 +1123,7 @@ void acpi_turn_off_unused_power_resources(void)
10461123
{
10471124
struct acpi_power_resource *resource;
10481125

1049-
if (dmi_check_system(dmi_leave_unused_power_resources_on))
1126+
if (unused_power_resources_quirk)
10501127
return;
10511128

10521129
mutex_lock(&power_resource_list_lock);
@@ -1065,3 +1142,10 @@ void acpi_turn_off_unused_power_resources(void)
10651142

10661143
mutex_unlock(&power_resource_list_lock);
10671144
}
1145+
1146+
void __init acpi_power_resources_init(void)
1147+
{
1148+
hp_eb_gp12pxp_quirk = dmi_check_system(dmi_hp_elitebook_gp12pxp_quirk);
1149+
unused_power_resources_quirk =
1150+
dmi_check_system(dmi_leave_unused_power_resources_on);
1151+
}

drivers/acpi/property.c

Lines changed: 96 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ static bool acpi_nondev_subnode_extract(union acpi_object *desc,
8383
struct fwnode_handle *parent)
8484
{
8585
struct acpi_data_node *dn;
86+
acpi_handle scope = NULL;
8687
bool result;
8788

8889
if (acpi_graph_ignore_port(handle))
@@ -98,69 +99,62 @@ static bool acpi_nondev_subnode_extract(union acpi_object *desc,
9899
INIT_LIST_HEAD(&dn->data.properties);
99100
INIT_LIST_HEAD(&dn->data.subnodes);
100101

101-
result = acpi_extract_properties(handle, desc, &dn->data);
102-
103-
if (handle) {
104-
acpi_handle scope;
105-
acpi_status status;
102+
/*
103+
* The scope for the completion of relative pathname segments and
104+
* subnode object lookup is the one of the namespace node (device)
105+
* containing the object that has returned the package. That is, it's
106+
* the scope of that object's parent device.
107+
*/
108+
if (handle)
109+
acpi_get_parent(handle, &scope);
106110

107-
/*
108-
* The scope for the subnode object lookup is the one of the
109-
* namespace node (device) containing the object that has
110-
* returned the package. That is, it's the scope of that
111-
* object's parent.
112-
*/
113-
status = acpi_get_parent(handle, &scope);
114-
if (ACPI_SUCCESS(status)
115-
&& acpi_enumerate_nondev_subnodes(scope, desc, &dn->data,
116-
&dn->fwnode))
117-
result = true;
118-
} else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data,
119-
&dn->fwnode)) {
111+
/*
112+
* Extract properties from the _DSD-equivalent package pointed to by
113+
* desc and use scope (if not NULL) for the completion of relative
114+
* pathname segments.
115+
*
116+
* The extracted properties will be held in the new data node dn.
117+
*/
118+
result = acpi_extract_properties(scope, desc, &dn->data);
119+
/*
120+
* Look for subnodes in the _DSD-equivalent package pointed to by desc
121+
* and create child nodes of dn if there are any.
122+
*/
123+
if (acpi_enumerate_nondev_subnodes(scope, desc, &dn->data, &dn->fwnode))
120124
result = true;
121-
}
122-
123-
if (result) {
124-
dn->handle = handle;
125-
dn->data.pointer = desc;
126-
list_add_tail(&dn->sibling, list);
127-
return true;
128-
}
129-
130-
kfree(dn);
131-
acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n");
132-
return false;
133-
}
134125

135-
static bool acpi_nondev_subnode_data_ok(acpi_handle handle,
136-
const union acpi_object *link,
137-
struct list_head *list,
138-
struct fwnode_handle *parent)
139-
{
140-
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
141-
acpi_status status;
142-
143-
status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
144-
ACPI_TYPE_PACKAGE);
145-
if (ACPI_FAILURE(status))
126+
if (!result) {
127+
kfree(dn);
128+
acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n");
146129
return false;
130+
}
147131

148-
if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list,
149-
parent))
150-
return true;
132+
/*
133+
* This will be NULL if the desc package is embedded in an outer
134+
* _DSD-equivalent package and its scope cannot be determined.
135+
*/
136+
dn->handle = handle;
137+
dn->data.pointer = desc;
138+
list_add_tail(&dn->sibling, list);
151139

152-
ACPI_FREE(buf.pointer);
153-
return false;
140+
return true;
154141
}
155142

156143
static bool acpi_nondev_subnode_ok(acpi_handle scope,
157144
const union acpi_object *link,
158145
struct list_head *list,
159146
struct fwnode_handle *parent)
160147
{
148+
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
161149
acpi_handle handle;
162150
acpi_status status;
163151

152+
/*
153+
* If the scope is unknown, the _DSD-equivalent package being parsed
154+
* was embedded in an outer _DSD-equivalent package as a result of
155+
* direct evaluation of an object pointed to by a reference. In that
156+
* case, using a pathname as the target object pointer is invalid.
157+
*/
164158
if (!scope)
165159
return false;
166160

@@ -169,7 +163,17 @@ static bool acpi_nondev_subnode_ok(acpi_handle scope,
169163
if (ACPI_FAILURE(status))
170164
return false;
171165

172-
return acpi_nondev_subnode_data_ok(handle, link, list, parent);
166+
status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
167+
ACPI_TYPE_PACKAGE);
168+
if (ACPI_FAILURE(status))
169+
return false;
170+
171+
if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list,
172+
parent))
173+
return true;
174+
175+
ACPI_FREE(buf.pointer);
176+
return false;
173177
}
174178

175179
static bool acpi_add_nondev_subnodes(acpi_handle scope,
@@ -180,36 +184,66 @@ static bool acpi_add_nondev_subnodes(acpi_handle scope,
180184
bool ret = false;
181185
int i;
182186

187+
/*
188+
* Every element in the links package is expected to represent a link
189+
* to a non-device node in a tree containing device-specific data.
190+
*/
183191
for (i = 0; i < links->package.count; i++) {
184192
union acpi_object *link, *desc;
185-
acpi_handle handle;
186193
bool result;
187194

188195
link = &links->package.elements[i];
189196
/* Only two elements allowed. */
190197
if (link->package.count != 2)
191198
continue;
192199

193-
/* The first one must be a string. */
200+
/* The first one (the key) must be a string. */
194201
if (link->package.elements[0].type != ACPI_TYPE_STRING)
195202
continue;
196203

197-
/* The second one may be a string, a reference or a package. */
204+
/* The second one (the target) may be a string or a package. */
198205
switch (link->package.elements[1].type) {
199206
case ACPI_TYPE_STRING:
207+
/*
208+
* The string is expected to be a full pathname or a
209+
* pathname segment relative to the given scope. That
210+
* pathname is expected to point to an object returning
211+
* a package that contains _DSD-equivalent information.
212+
*/
200213
result = acpi_nondev_subnode_ok(scope, link, list,
201214
parent);
202215
break;
203-
case ACPI_TYPE_LOCAL_REFERENCE:
204-
handle = link->package.elements[1].reference.handle;
205-
result = acpi_nondev_subnode_data_ok(handle, link, list,
206-
parent);
207-
break;
208216
case ACPI_TYPE_PACKAGE:
217+
/*
218+
* This happens when a reference is used in AML to
219+
* point to the target. Since the target is expected
220+
* to be a named object, a reference to it will cause it
221+
* to be avaluated in place and its return package will
222+
* be embedded in the links package at the location of
223+
* the reference.
224+
*
225+
* The target package is expected to contain _DSD-
226+
* equivalent information, but the scope in which it
227+
* is located in the original AML is unknown. Thus
228+
* it cannot contain pathname segments represented as
229+
* strings because there is no way to build full
230+
* pathnames out of them.
231+
*/
232+
acpi_handle_debug(scope, "subnode %s: Unknown scope\n",
233+
link->package.elements[0].string.pointer);
209234
desc = &link->package.elements[1];
210235
result = acpi_nondev_subnode_extract(desc, NULL, link,
211236
list, parent);
212237
break;
238+
case ACPI_TYPE_LOCAL_REFERENCE:
239+
/*
240+
* It is not expected to see any local references in
241+
* the links package because referencing a named object
242+
* should cause it to be evaluated in place.
243+
*/
244+
acpi_handle_info(scope, "subnode %s: Unexpected reference\n",
245+
link->package.elements[0].string.pointer);
246+
fallthrough;
213247
default:
214248
result = false;
215249
break;
@@ -369,6 +403,9 @@ static void acpi_untie_nondev_subnodes(struct acpi_device_data *data)
369403
struct acpi_data_node *dn;
370404

371405
list_for_each_entry(dn, &data->subnodes, sibling) {
406+
if (!dn->handle)
407+
continue;
408+
372409
acpi_detach_data(dn->handle, acpi_nondev_subnode_tag);
373410

374411
acpi_untie_nondev_subnodes(&dn->data);
@@ -383,6 +420,9 @@ static bool acpi_tie_nondev_subnodes(struct acpi_device_data *data)
383420
acpi_status status;
384421
bool ret;
385422

423+
if (!dn->handle)
424+
continue;
425+
386426
status = acpi_attach_data(dn->handle, acpi_nondev_subnode_tag, dn);
387427
if (ACPI_FAILURE(status) && status != AE_ALREADY_EXISTS) {
388428
acpi_handle_err(dn->handle, "Can't tag data node\n");

drivers/acpi/resource.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,13 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = {
510510
DMI_MATCH(DMI_BOARD_NAME, "N6506M"),
511511
},
512512
},
513+
{
514+
/* Asus Vivobook Pro N6506CU* */
515+
.matches = {
516+
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
517+
DMI_MATCH(DMI_BOARD_NAME, "N6506CU"),
518+
},
519+
},
513520
{
514521
/* LG Electronics 17U70P */
515522
.matches = {

drivers/acpi/scan.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2704,6 +2704,7 @@ void __init acpi_scan_init(void)
27042704
acpi_memory_hotplug_init();
27052705
acpi_watchdog_init();
27062706
acpi_pnp_init();
2707+
acpi_power_resources_init();
27072708
acpi_int340x_thermal_init();
27082709
acpi_init_lpit();
27092710

0 commit comments

Comments
 (0)