Skip to content

Commit ca84f18

Browse files
committed
ACPI: power: Save the last known state of each power resource
Currently, there are two ways to check the state of an ACPI power resource and they may not be consistent with each other. The first one is to evaluate the power resource's _STA object and the other one is to check its reference counter value. However, on some systems the value returned by _STA may not be consistent with the value of the power resource's reference counter (for example, on some systems it returns the same value every time for certain power resources). Moreover, evaluating _STA is unnecessary overhead for a power resource for which it has been evaluated already or whose state is otherwise known, because either the _ON or the _OFF method has been executed for it. For this reason, save the state of each power resource in its struct acpi_power_resource object and use the saved value whenever its state needs to be checked, except when its stats is unknown, in which case the _STA method is evaluated for it and the value returned by that method is saved as the last known state of the power resource. Moreover, drop the power resource _STA method evaluation from acpi_add_power_resource(), so as to avoid doing that unnecessarily for power resources that will never be used. Tested-by: Dave Olsthoorn <dave@bewaar.me> Tested-by: Shujun Wang <wsj20369@163.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent 587024b commit ca84f18

1 file changed

Lines changed: 32 additions & 18 deletions

File tree

drivers/acpi/power.c

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ struct acpi_power_resource {
5353
u32 order;
5454
unsigned int ref_count;
5555
unsigned int users;
56+
u8 state;
5657
bool wakeup_enabled;
5758
struct mutex resource_lock;
5859
struct list_head dependents;
@@ -182,15 +183,12 @@ int acpi_extract_power_resources(union acpi_object *package, unsigned int start,
182183
return err;
183184
}
184185

185-
static int acpi_power_get_state(acpi_handle handle, u8 *state)
186+
static int __get_state(acpi_handle handle, u8 *state)
186187
{
187188
acpi_status status = AE_OK;
188189
unsigned long long sta = 0;
189190
u8 cur_state;
190191

191-
if (!handle || !state)
192-
return -EINVAL;
193-
194192
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
195193
if (ACPI_FAILURE(status))
196194
return -ENODEV;
@@ -204,6 +202,20 @@ static int acpi_power_get_state(acpi_handle handle, u8 *state)
204202
return 0;
205203
}
206204

205+
static int acpi_power_get_state(struct acpi_power_resource *resource, u8 *state)
206+
{
207+
if (resource->state == ACPI_POWER_RESOURCE_STATE_UNKNOWN) {
208+
int ret;
209+
210+
ret = __get_state(resource->device.handle, &resource->state);
211+
if (ret)
212+
return ret;
213+
}
214+
215+
*state = resource->state;
216+
return 0;
217+
}
218+
207219
static int acpi_power_get_list_state(struct list_head *list, u8 *state)
208220
{
209221
struct acpi_power_resource_entry *entry;
@@ -215,11 +227,10 @@ static int acpi_power_get_list_state(struct list_head *list, u8 *state)
215227
/* The state of the list is 'on' IFF all resources are 'on'. */
216228
list_for_each_entry(entry, list, node) {
217229
struct acpi_power_resource *resource = entry->resource;
218-
acpi_handle handle = resource->device.handle;
219230
int result;
220231

221232
mutex_lock(&resource->resource_lock);
222-
result = acpi_power_get_state(handle, &cur_state);
233+
result = acpi_power_get_state(resource, &cur_state);
223234
mutex_unlock(&resource->resource_lock);
224235
if (result)
225236
return result;
@@ -352,8 +363,12 @@ static int __acpi_power_on(struct acpi_power_resource *resource)
352363
acpi_status status = AE_OK;
353364

354365
status = acpi_evaluate_object(resource->device.handle, "_ON", NULL, NULL);
355-
if (ACPI_FAILURE(status))
366+
if (ACPI_FAILURE(status)) {
367+
resource->state = ACPI_POWER_RESOURCE_STATE_UNKNOWN;
356368
return -ENODEV;
369+
}
370+
371+
resource->state = ACPI_POWER_RESOURCE_STATE_ON;
357372

358373
pr_debug("Power resource [%s] turned on\n", resource->name);
359374

@@ -405,8 +420,12 @@ static int __acpi_power_off(struct acpi_power_resource *resource)
405420

406421
status = acpi_evaluate_object(resource->device.handle, "_OFF",
407422
NULL, NULL);
408-
if (ACPI_FAILURE(status))
423+
if (ACPI_FAILURE(status)) {
424+
resource->state = ACPI_POWER_RESOURCE_STATE_UNKNOWN;
409425
return -ENODEV;
426+
}
427+
428+
resource->state = ACPI_POWER_RESOURCE_STATE_OFF;
410429

411430
pr_debug("Power resource [%s] turned off\n", resource->name);
412431

@@ -590,13 +609,12 @@ int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p)
590609

591610
list_for_each_entry(entry, list, node) {
592611
struct acpi_power_resource *resource = entry->resource;
593-
acpi_handle handle = resource->device.handle;
594612
int result;
595613
u8 state;
596614

597615
mutex_lock(&resource->resource_lock);
598616

599-
result = acpi_power_get_state(handle, &state);
617+
result = acpi_power_get_state(resource, &state);
600618
if (result) {
601619
mutex_unlock(&resource->resource_lock);
602620
return result;
@@ -920,7 +938,6 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle)
920938
struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object };
921939
acpi_status status;
922940
int result;
923-
u8 state;
924941

925942
acpi_bus_get_device(handle, &device);
926943
if (device)
@@ -947,13 +964,9 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle)
947964

948965
resource->system_level = acpi_object.power_resource.system_level;
949966
resource->order = acpi_object.power_resource.resource_order;
967+
resource->state = ACPI_POWER_RESOURCE_STATE_UNKNOWN;
950968

951-
result = acpi_power_get_state(handle, &state);
952-
if (result)
953-
goto err;
954-
955-
pr_info("%s [%s] (%s)\n", acpi_device_name(device),
956-
acpi_device_bid(device), state ? "on" : "off");
969+
pr_info("%s [%s]\n", acpi_device_name(device), acpi_device_bid(device));
957970

958971
device->flags.match_driver = true;
959972
result = acpi_device_add(device, acpi_release_power_resource);
@@ -985,7 +998,8 @@ void acpi_resume_power_resources(void)
985998

986999
mutex_lock(&resource->resource_lock);
9871000

988-
result = acpi_power_get_state(resource->device.handle, &state);
1001+
resource->state = ACPI_POWER_RESOURCE_STATE_UNKNOWN;
1002+
result = acpi_power_get_state(resource, &state);
9891003
if (result) {
9901004
mutex_unlock(&resource->resource_lock);
9911005
continue;

0 commit comments

Comments
 (0)