Commit 56db6a8e authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

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
parents 0960a3cb 1c2a66d4
Loading
Loading
Loading
Loading
+65 −34
Original line number Diff line number Diff line
@@ -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->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;
					}
				}

				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);
				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;
					}
				}
				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 @@ static void lpi_device_get_constraints(void)
	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));
	}
}
+8 −2
Original line number Diff line number Diff line
@@ -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