diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-06-29 13:39:41 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-06-29 13:39:41 -0700 |
| commit | 5e6928249b81b4d8727ab6a4037a171d15455cb0 (patch) | |
| tree | a07c72776c9626cb64d17f9c412c7d176ea7f6c3 /drivers/acpi/power.c | |
| parent | 3563f55ce65462063543dfa6a8d8c7fbfb9d7772 (diff) | |
| parent | 64f9111dd6225a50b8fdd365dfdda275c2a708c0 (diff) | |
| download | linux-5e6928249b81b4d8727ab6a4037a171d15455cb0.tar.gz linux-5e6928249b81b4d8727ab6a4037a171d15455cb0.tar.bz2 linux-5e6928249b81b4d8727ab6a4037a171d15455cb0.zip | |
Merge tag 'acpi-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull ACPI updates from Rafael Wysocki:
"These update the ACPICA code in the kernel to the 20210604 upstream
revision, add preliminary support for the Platform Runtime Mechanism
(PRM), address issues related to the handling of device dependencies
in the ACPI device eunmeration code, improve the tracking of ACPI
power resource states, improve the ACPI support for suspend-to-idle on
AMD systems, continue the unification of message printing in the ACPI
code, address assorted issues and clean up the code in a number of
places.
Specifics:
- Update ACPICA code in the kernel to upstrea revision 20210604
including the following changes:
- Add defines for the CXL Host Bridge Structureand and add the
CFMWS structure definition to CEDT (Alison Schofield).
- iASL: Finish support for the IVRS ACPI table (Bob Moore).
- iASL: Add support for the SVKL table (Bob Moore).
- iASL: Add full support for RGRT ACPI table (Bob Moore).
- iASL: Add support for the BDAT ACPI table (Bob Moore).
- iASL: add disassembler support for PRMT (Erik Kaneda).
- Fix memory leak caused by _CID repair function (Erik Kaneda).
- Add support for PlatformRtMechanism OpRegion (Erik Kaneda).
- Add PRMT module header to facilitate parsing (Erik Kaneda).
- Add _PLD panel positions (Fabian Wüthrich).
- MADT: add Multiprocessor Wakeup Mailbox Structure and the SVKL
table headers (Kuppuswamy Sathyanarayanan).
- Use ACPI_FALLTHROUGH (Wei Ming Chen).
- Add preliminary support for the Platform Runtime Mechanism (PRM) to
allow the AML interpreter to call PRM functions (Erik Kaneda).
- Address some issues related to the handling of device dependencies
reported by _DEP in the ACPI device enumeration code and clean up
some related pieces of it (Rafael Wysocki).
- Improve the tracking of states of ACPI power resources (Rafael
Wysocki).
- Improve ACPI support for suspend-to-idle on AMD systems (Alex
Deucher, Mario Limonciello, Pratik Vishwakarma).
- Continue the unification and cleanup of message printing in the
ACPI code (Hanjun Guo, Heiner Kallweit).
- Fix possible buffer overrun issue with the description_show() sysfs
attribute method (Krzysztof Wilczyński).
- Improve the acpi_mask_gpe kernel command line parameter handling
and clean up the core ACPI code related to sysfs (Andy Shevchenko,
Baokun Li, Clayton Casciato).
- Postpone bringing devices in the general ACPI PM domain to D0
during resume from system-wide suspend until they are really needed
(Dmitry Torokhov).
- Make the ACPI processor driver fix up C-state latency if not
ordered (Mario Limonciello).
- Add support for identifying devices depening on the given one that
are not its direct descendants with the help of _DEP (Daniel
Scally).
- Extend the checks related to ACPI IRQ overrides on x86 in order to
avoid false-positives (Hui Wang).
- Add battery DPTF participant for Intel SoCs (Sumeet Pawnikar).
- Rearrange the ACPI fan driver and device power management code to
use a common list of device IDs (Rafael Wysocki).
- Fix clang CFI violation in the ACPI BGRT table parsing code and
clean it up (Nathan Chancellor).
- Add GPE-related quirks for some laptops to the EC driver (Chris
Chiu, Zhang Rui).
- Make the ACPI PPTT table parsing code populate the cache-id value
if present in the firmware (James Morse).
- Remove redundant clearing of context->ret.pointer from
acpi_run_osc() (Hans de Goede).
- Add missing acpi_put_table() in acpi_init_fpdt() (Jing Xiangfeng).
- Make ACPI APEI handle ARM Processor Error CPER records like Memory
Error ones to avoid user space task lockups (Xiaofei Tan).
- Stop warning about disabled ACPI in APEI (Jon Hunter).
- Fix fall-through warning for Clang in the SBSHC driver (Gustavo A.
R. Silva).
- Add custom DSDT file as Makefile prerequisite (Richard Fitzgerald).
- Initialize local variable to avoid garbage being returned (Colin
Ian King).
- Simplify assorted pieces of code, address assorted coding style and
documentation issues and comment typos (Baokun Li, Christophe
JAILLET, Clayton Casciato, Liu Shixin, Shaokun Zhang, Wei Yongjun,
Yang Li, Zhen Lei)"
* tag 'acpi-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (97 commits)
ACPI: PM: postpone bringing devices to D0 unless we need them
ACPI: tables: Add custom DSDT file as makefile prerequisite
ACPI: bgrt: Use sysfs_emit
ACPI: bgrt: Fix CFI violation
ACPI: EC: trust DSDT GPE for certain HP laptop
ACPI: scan: Simplify acpi_table_events_fn()
ACPI: PM: Adjust behavior for field problems on AMD systems
ACPI: PM: s2idle: Add support for new Microsoft UUID
ACPI: PM: s2idle: Add support for multiple func mask
ACPI: PM: s2idle: Refactor common code
ACPI: PM: s2idle: Use correct revision id
ACPI: sysfs: Remove tailing return statement in void function
ACPI: sysfs: Use __ATTR_RO() and __ATTR_RW() macros
ACPI: sysfs: Sort headers alphabetically
ACPI: sysfs: Refactor param_get_trace_state() to drop dead code
ACPI: sysfs: Unify pattern of memory allocations
ACPI: sysfs: Allow bitmap list to be supplied to acpi_mask_gpe
ACPI: sysfs: Make sparse happy about address space in use
ACPI: scan: Fix race related to dropping dependencies
ACPI: scan: Reorganize acpi_device_add()
...
Diffstat (limited to 'drivers/acpi/power.c')
| -rw-r--r-- | drivers/acpi/power.c | 116 |
1 files changed, 55 insertions, 61 deletions
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 97c9a94a1a30..eba7785047ca 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -52,7 +52,7 @@ struct acpi_power_resource { u32 system_level; u32 order; unsigned int ref_count; - unsigned int users; + u8 state; bool wakeup_enabled; struct mutex resource_lock; struct list_head dependents; @@ -173,8 +173,6 @@ int acpi_extract_power_resources(union acpi_object *package, unsigned int start, err = acpi_power_resources_list_add(rhandle, list); if (err) break; - - to_power_resource(rdev)->users++; } if (err) acpi_power_resources_list_free(list); @@ -182,44 +180,54 @@ int acpi_extract_power_resources(union acpi_object *package, unsigned int start, return err; } -static int acpi_power_get_state(acpi_handle handle, int *state) +static int __get_state(acpi_handle handle, u8 *state) { acpi_status status = AE_OK; unsigned long long sta = 0; - - if (!handle || !state) - return -EINVAL; + u8 cur_state; status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); if (ACPI_FAILURE(status)) return -ENODEV; - *state = (sta & 0x01)?ACPI_POWER_RESOURCE_STATE_ON: - ACPI_POWER_RESOURCE_STATE_OFF; + cur_state = sta & ACPI_POWER_RESOURCE_STATE_ON; acpi_handle_debug(handle, "Power resource is %s\n", - *state ? "on" : "off"); + cur_state ? "on" : "off"); + + *state = cur_state; + return 0; +} + +static int acpi_power_get_state(struct acpi_power_resource *resource, u8 *state) +{ + if (resource->state == ACPI_POWER_RESOURCE_STATE_UNKNOWN) { + int ret; + ret = __get_state(resource->device.handle, &resource->state); + if (ret) + return ret; + } + + *state = resource->state; return 0; } -static int acpi_power_get_list_state(struct list_head *list, int *state) +static int acpi_power_get_list_state(struct list_head *list, u8 *state) { struct acpi_power_resource_entry *entry; - int cur_state; + u8 cur_state = ACPI_POWER_RESOURCE_STATE_OFF; if (!list || !state) return -EINVAL; /* The state of the list is 'on' IFF all resources are 'on'. */ - cur_state = 0; list_for_each_entry(entry, list, node) { struct acpi_power_resource *resource = entry->resource; - acpi_handle handle = resource->device.handle; int result; mutex_lock(&resource->resource_lock); - result = acpi_power_get_state(handle, &cur_state); + result = acpi_power_get_state(resource, &cur_state); mutex_unlock(&resource->resource_lock); if (result) return result; @@ -352,8 +360,12 @@ static int __acpi_power_on(struct acpi_power_resource *resource) acpi_status status = AE_OK; status = acpi_evaluate_object(resource->device.handle, "_ON", NULL, NULL); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { + resource->state = ACPI_POWER_RESOURCE_STATE_UNKNOWN; return -ENODEV; + } + + resource->state = ACPI_POWER_RESOURCE_STATE_ON; pr_debug("Power resource [%s] turned on\n", resource->name); @@ -405,8 +417,12 @@ static int __acpi_power_off(struct acpi_power_resource *resource) status = acpi_evaluate_object(resource->device.handle, "_OFF", NULL, NULL); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { + resource->state = ACPI_POWER_RESOURCE_STATE_UNKNOWN; return -ENODEV; + } + + resource->state = ACPI_POWER_RESOURCE_STATE_OFF; pr_debug("Power resource [%s] turned off\n", resource->name); @@ -590,13 +606,12 @@ int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p) list_for_each_entry(entry, list, node) { struct acpi_power_resource *resource = entry->resource; - acpi_handle handle = resource->device.handle; int result; - int state; + u8 state; mutex_lock(&resource->resource_lock); - result = acpi_power_get_state(handle, &state); + result = acpi_power_get_state(resource, &state); if (result) { mutex_unlock(&resource->resource_lock); return result; @@ -789,8 +804,8 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) int acpi_power_get_inferred_state(struct acpi_device *device, int *state) { + u8 list_state = ACPI_POWER_RESOURCE_STATE_OFF; int result = 0; - int list_state = 0; int i = 0; if (!device || !state) @@ -919,7 +934,7 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle) union acpi_object acpi_object; struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object }; acpi_status status; - int state, result = -ENODEV; + int result; acpi_bus_get_device(handle, &device); if (device) @@ -946,13 +961,9 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle) resource->system_level = acpi_object.power_resource.system_level; resource->order = acpi_object.power_resource.resource_order; + resource->state = ACPI_POWER_RESOURCE_STATE_UNKNOWN; - result = acpi_power_get_state(handle, &state); - if (result) - goto err; - - pr_info("%s [%s] (%s)\n", acpi_device_name(device), - acpi_device_bid(device), state ? "on" : "off"); + pr_info("%s [%s]\n", acpi_device_name(device), acpi_device_bid(device)); device->flags.match_driver = true; result = acpi_device_add(device, acpi_release_power_resource); @@ -979,11 +990,13 @@ void acpi_resume_power_resources(void) mutex_lock(&power_resource_list_lock); list_for_each_entry(resource, &acpi_power_resource_list, list_node) { - int result, state; + int result; + u8 state; mutex_lock(&resource->resource_lock); - result = acpi_power_get_state(resource->device.handle, &state); + resource->state = ACPI_POWER_RESOURCE_STATE_UNKNOWN; + result = acpi_power_get_state(resource, &state); if (result) { mutex_unlock(&resource->resource_lock); continue; @@ -991,7 +1004,7 @@ void acpi_resume_power_resources(void) if (state == ACPI_POWER_RESOURCE_STATE_OFF && resource->ref_count) { - dev_info(&resource->device.dev, "Turning ON\n"); + dev_dbg(&resource->device.dev, "Turning ON\n"); __acpi_power_on(resource); } @@ -1002,38 +1015,10 @@ void acpi_resume_power_resources(void) } #endif -static void acpi_power_turn_off_if_unused(struct acpi_power_resource *resource, - bool init) -{ - if (resource->ref_count > 0) - return; - - if (init) { - if (resource->users > 0) - return; - } else { - int result, state; - - result = acpi_power_get_state(resource->device.handle, &state); - if (result || state == ACPI_POWER_RESOURCE_STATE_OFF) - return; - } - - dev_info(&resource->device.dev, "Turning OFF\n"); - __acpi_power_off(resource); -} - /** * acpi_turn_off_unused_power_resources - Turn off power resources not in use. - * @init: Control switch. - * - * If @ainit is set, unconditionally turn off all of the ACPI power resources - * without any users. - * - * Otherwise, turn off all ACPI power resources without active references (that - * is, the ones that should be "off" at the moment) that are "on". */ -void acpi_turn_off_unused_power_resources(bool init) +void acpi_turn_off_unused_power_resources(void) { struct acpi_power_resource *resource; @@ -1042,7 +1027,16 @@ void acpi_turn_off_unused_power_resources(bool init) list_for_each_entry_reverse(resource, &acpi_power_resource_list, list_node) { mutex_lock(&resource->resource_lock); - acpi_power_turn_off_if_unused(resource, init); + /* + * Turn off power resources in an unknown state too, because the + * platform firmware on some system expects the OS to turn off + * power resources without any users unconditionally. + */ + if (!resource->ref_count && + resource->state != ACPI_POWER_RESOURCE_STATE_OFF) { + dev_dbg(&resource->device.dev, "Turning OFF\n"); + __acpi_power_off(resource); + } mutex_unlock(&resource->resource_lock); } |
