Merge branch 'acpi-pm'

Merge ACPI power management updates for 6.6-rc1:

 - Fix and clean up suspend-to-idle interface for AMD systems (Mario
   Limonciello, Andy Shevchenko).

* acpi-pm:
  ACPI: x86: s2idle: Add a function to get LPS0 constraint for a device
  ACPI: x86: s2idle: Add for_each_lpi_constraint() helper
  ACPI: x86: s2idle: Add more debugging for AMD constraints parsing
  ACPI: x86: s2idle: Fix a logic error parsing AMD constraints table
  ACPI: x86: s2idle: Catch multiple ACPI_TYPE_PACKAGE objects
  ACPI: x86: s2idle: Post-increment variables when getting constraints
  ACPI: Adjust #ifdef for *_lps0_dev use
This commit is contained in:
Rafael J. Wysocki 2023-08-25 20:55:47 +02:00
commit 56db6a8e5a
2 changed files with 77 additions and 40 deletions

View File

@ -94,6 +94,11 @@ static struct lpi_constraints *lpi_constraints_table;
static int lpi_constraints_table_size;
static int rev_id;
#define for_each_lpi_constraint(entry) \
for (int i = 0; \
entry = &lpi_constraints_table[i], i < lpi_constraints_table_size; \
i++)
static void lpi_device_get_constraints_amd(void)
{
union acpi_object *out_obj;
@ -113,6 +118,12 @@ static void lpi_device_get_constraints_amd(void)
union acpi_object *package = &out_obj->package.elements[i];
if (package->type == ACPI_TYPE_PACKAGE) {
if (lpi_constraints_table) {
acpi_handle_err(lps0_device_handle,
"Duplicate constraints list\n");
goto free_acpi_buffer;
}
lpi_constraints_table = kcalloc(package->package.count,
sizeof(*lpi_constraints_table),
GFP_KERNEL);
@ -123,17 +134,16 @@ static void lpi_device_get_constraints_amd(void)
acpi_handle_debug(lps0_device_handle,
"LPI: constraints list begin:\n");
for (j = 0; j < package->package.count; ++j) {
for (j = 0; j < package->package.count; j++) {
union acpi_object *info_obj = &package->package.elements[j];
struct lpi_device_constraint_amd dev_info = {};
struct lpi_constraints *list;
acpi_status status;
for (k = 0; k < info_obj->package.count; ++k) {
union acpi_object *obj = &info_obj->package.elements[k];
list = &lpi_constraints_table[lpi_constraints_table_size];
list = &lpi_constraints_table[lpi_constraints_table_size];
list->min_dstate = -1;
for (k = 0; k < info_obj->package.count; k++) {
union acpi_object *obj = &info_obj->package.elements[k];
switch (k) {
case 0:
@ -149,27 +159,25 @@ static void lpi_device_get_constraints_amd(void)
dev_info.min_dstate = obj->integer.value;
break;
}
if (!dev_info.enabled || !dev_info.name ||
!dev_info.min_dstate)
continue;
status = acpi_get_handle(NULL, dev_info.name,
&list->handle);
if (ACPI_FAILURE(status))
continue;
acpi_handle_debug(lps0_device_handle,
"Name:%s\n", dev_info.name);
list->min_dstate = dev_info.min_dstate;
if (list->min_dstate < 0) {
acpi_handle_debug(lps0_device_handle,
"Incomplete constraint defined\n");
continue;
}
}
acpi_handle_debug(lps0_device_handle,
"Name:%s, Enabled: %d, States: %d, MinDstate: %d\n",
dev_info.name,
dev_info.enabled,
dev_info.function_states,
dev_info.min_dstate);
if (!dev_info.enabled || !dev_info.name ||
!dev_info.min_dstate)
continue;
status = acpi_get_handle(NULL, dev_info.name, &list->handle);
if (ACPI_FAILURE(status))
continue;
list->min_dstate = dev_info.min_dstate;
lpi_constraints_table_size++;
}
}
@ -214,7 +222,7 @@ static void lpi_device_get_constraints(void)
if (!package)
continue;
for (j = 0; j < package->package.count; ++j) {
for (j = 0; j < package->package.count; j++) {
union acpi_object *element =
&(package->package.elements[j]);
@ -246,7 +254,7 @@ static void lpi_device_get_constraints(void)
constraint->min_dstate = -1;
for (j = 0; j < package_count; ++j) {
for (j = 0; j < package_count; j++) {
union acpi_object *info_obj = &info.package[j];
union acpi_object *cnstr_pkg;
union acpi_object *obj;
@ -291,32 +299,55 @@ free_acpi_buffer:
ACPI_FREE(out_obj);
}
/**
* acpi_get_lps0_constraint - Get the LPS0 constraint for a device.
* @adev: Device to get the constraint for.
*
* The LPS0 constraint is the shallowest (minimum) power state in which the
* device can be so as to allow the platform as a whole to achieve additional
* energy conservation by utilizing a system-wide low-power state.
*
* Returns:
* - ACPI power state value of the constraint for @adev on success.
* - Otherwise, ACPI_STATE_UNKNOWN.
*/
int acpi_get_lps0_constraint(struct acpi_device *adev)
{
struct lpi_constraints *entry;
for_each_lpi_constraint(entry) {
if (adev->handle == entry->handle)
return entry->min_dstate;
}
return ACPI_STATE_UNKNOWN;
}
static void lpi_check_constraints(void)
{
int i;
struct lpi_constraints *entry;
for (i = 0; i < lpi_constraints_table_size; ++i) {
acpi_handle handle = lpi_constraints_table[i].handle;
struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
for_each_lpi_constraint(entry) {
struct acpi_device *adev = acpi_fetch_acpi_dev(entry->handle);
if (!adev)
continue;
acpi_handle_debug(handle,
acpi_handle_debug(entry->handle,
"LPI: required min power state:%s current power state:%s\n",
acpi_power_state_string(lpi_constraints_table[i].min_dstate),
acpi_power_state_string(entry->min_dstate),
acpi_power_state_string(adev->power.state));
if (!adev->flags.power_manageable) {
acpi_handle_info(handle, "LPI: Device not power manageable\n");
lpi_constraints_table[i].handle = NULL;
acpi_handle_info(entry->handle, "LPI: Device not power manageable\n");
entry->handle = NULL;
continue;
}
if (adev->power.state < lpi_constraints_table[i].min_dstate)
acpi_handle_info(handle,
if (adev->power.state < entry->min_dstate)
acpi_handle_info(entry->handle,
"LPI: Constraint not met; min power state:%s current power state:%s\n",
acpi_power_state_string(lpi_constraints_table[i].min_dstate),
acpi_power_state_string(entry->min_dstate),
acpi_power_state_string(adev->power.state));
}
}

View File

@ -1098,7 +1098,7 @@ void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state,
acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state,
u32 val_a, u32 val_b);
#ifdef CONFIG_X86
#if defined(CONFIG_SUSPEND) && defined(CONFIG_X86)
struct acpi_s2idle_dev_ops {
struct list_head list_node;
void (*prepare)(void);
@ -1107,7 +1107,13 @@ struct acpi_s2idle_dev_ops {
};
int acpi_register_lps0_dev(struct acpi_s2idle_dev_ops *arg);
void acpi_unregister_lps0_dev(struct acpi_s2idle_dev_ops *arg);
#endif /* CONFIG_X86 */
int acpi_get_lps0_constraint(struct acpi_device *adev);
#else /* CONFIG_SUSPEND && CONFIG_X86 */
static inline int acpi_get_lps0_constraint(struct device *dev)
{
return ACPI_STATE_UNKNOWN;
}
#endif /* CONFIG_SUSPEND && CONFIG_X86 */
#ifndef CONFIG_IA64
void arch_reserve_mem_area(acpi_physical_address addr, size_t size);
#else