Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7b01463e authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branch 'pm-sleep'

* pm-sleep:
  ACPI / PM: Check low power idle constraints for debug only
  PM / s2idle: Rename platform operations structure
  PM / s2idle: Rename ->enter_freeze to ->enter_s2idle
  PM / s2idle: Rename freeze_state enum and related items
  PM / s2idle: Rename PM_SUSPEND_FREEZE to PM_SUSPEND_TO_IDLE
  ACPI / PM: Prefer suspend-to-idle over S3 on some systems
  platform/x86: intel-hid: Wake up Dell Latitude 7275 from suspend-to-idle
  PM / suspend: Define pr_fmt() in suspend.c
  PM / suspend: Use mem_sleep_labels[] strings in messages
  PM / sleep: Put pm_test under CONFIG_PM_SLEEP_DEBUG
  PM / sleep: Check pm_wakeup_pending() in __device_suspend_noirq()
  PM / core: Add error argument to dpm_show_time()
  PM / core: Split dpm_suspend_noirq() and dpm_resume_noirq()
  PM / s2idle: Rearrange the main suspend-to-idle loop
  PM / timekeeping: Print debug messages when requested
  PM / sleep: Mark suspend/hibernation start and finish
  PM / sleep: Do not print debug messages by default
  PM / suspend: Export pm_suspend_target_state
parents a1b5fd8f 726fb6b4
Loading
Loading
Loading
Loading
+12 −0
Original line number Original line Diff line number Diff line
@@ -273,3 +273,15 @@ Description:


		This output is useful for system wakeup diagnostics of spurious
		This output is useful for system wakeup diagnostics of spurious
		wakeup interrupts.
		wakeup interrupts.

What:		/sys/power/pm_debug_messages
Date:		July 2017
Contact:	Rafael J. Wysocki <rjw@rjwysocki.net>
Description:
		The /sys/power/pm_debug_messages file controls the printing
		of debug messages from the system suspend/hiberbation
		infrastructure to the kernel log.

		Writing a "1" to this file enables the debug messages and
		writing a "0" (default) to it disables them.  Reads from
		this file return the current value.
+3 −1
Original line number Original line Diff line number Diff line
@@ -35,7 +35,9 @@ only one way to cause the system to go into the Suspend-To-RAM state (write
The default suspend mode (ie. the one to be used without writing anything into
The default suspend mode (ie. the one to be used without writing anything into
/sys/power/mem_sleep) is either "deep" (if Suspend-To-RAM is supported) or
/sys/power/mem_sleep) is either "deep" (if Suspend-To-RAM is supported) or
"s2idle", but it can be overridden by the value of the "mem_sleep_default"
"s2idle", but it can be overridden by the value of the "mem_sleep_default"
parameter in the kernel command line.
parameter in the kernel command line.  On some ACPI-based systems, depending on
the information in the FADT, the default may be "s2idle" even if Suspend-To-RAM
is supported.


The properties of all of the sleep states are described below.
The properties of all of the sleep states are described below.


+2 −2
Original line number Original line Diff line number Diff line
@@ -60,7 +60,7 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev,
	return index;
	return index;
}
}


static void tegra114_idle_enter_freeze(struct cpuidle_device *dev,
static void tegra114_idle_enter_s2idle(struct cpuidle_device *dev,
				       struct cpuidle_driver *drv,
				       struct cpuidle_driver *drv,
				       int index)
				       int index)
{
{
@@ -77,7 +77,7 @@ static struct cpuidle_driver tegra_idle_driver = {
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_PM_SLEEP
		[1] = {
		[1] = {
			.enter			= tegra114_idle_power_down,
			.enter			= tegra114_idle_power_down,
			.enter_freeze		= tegra114_idle_enter_freeze,
			.enter_s2idle		= tegra114_idle_enter_s2idle,
			.exit_latency		= 500,
			.exit_latency		= 500,
			.target_residency	= 1000,
			.target_residency	= 1000,
			.flags			= CPUIDLE_FLAG_TIMER_STOP,
			.flags			= CPUIDLE_FLAG_TIMER_STOP,
+3 −3
Original line number Original line Diff line number Diff line
@@ -791,7 +791,7 @@ static int acpi_idle_enter(struct cpuidle_device *dev,
	return index;
	return index;
}
}


static void acpi_idle_enter_freeze(struct cpuidle_device *dev,
static void acpi_idle_enter_s2idle(struct cpuidle_device *dev,
				   struct cpuidle_driver *drv, int index)
				   struct cpuidle_driver *drv, int index)
{
{
	struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
	struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
@@ -876,14 +876,14 @@ static int acpi_processor_setup_cstates(struct acpi_processor *pr)
			drv->safe_state_index = count;
			drv->safe_state_index = count;
		}
		}
		/*
		/*
		 * Halt-induced C1 is not good for ->enter_freeze, because it
		 * Halt-induced C1 is not good for ->enter_s2idle, because it
		 * re-enables interrupts on exit.  Moreover, C1 is generally not
		 * re-enables interrupts on exit.  Moreover, C1 is generally not
		 * particularly interesting from the suspend-to-idle angle, so
		 * particularly interesting from the suspend-to-idle angle, so
		 * avoid C1 and the situations in which we may need to fall back
		 * avoid C1 and the situations in which we may need to fall back
		 * to it altogether.
		 * to it altogether.
		 */
		 */
		if (cx->type != ACPI_STATE_C1 && !acpi_idle_fallback_to_c1(pr))
		if (cx->type != ACPI_STATE_C1 && !acpi_idle_fallback_to_c1(pr))
			state->enter_freeze = acpi_idle_enter_freeze;
			state->enter_s2idle = acpi_idle_enter_s2idle;


		count++;
		count++;
		if (count == CPUIDLE_STATE_MAX)
		if (count == CPUIDLE_STATE_MAX)
+188 −14
Original line number Original line Diff line number Diff line
@@ -669,6 +669,7 @@ static const struct acpi_device_id lps0_device_ids[] = {


#define ACPI_LPS0_DSM_UUID	"c4eb40a0-6cd2-11e2-bcfd-0800200c9a66"
#define ACPI_LPS0_DSM_UUID	"c4eb40a0-6cd2-11e2-bcfd-0800200c9a66"


#define ACPI_LPS0_GET_DEVICE_CONSTRAINTS	1
#define ACPI_LPS0_SCREEN_OFF	3
#define ACPI_LPS0_SCREEN_OFF	3
#define ACPI_LPS0_SCREEN_ON	4
#define ACPI_LPS0_SCREEN_ON	4
#define ACPI_LPS0_ENTRY		5
#define ACPI_LPS0_ENTRY		5
@@ -680,6 +681,166 @@ static acpi_handle lps0_device_handle;
static guid_t lps0_dsm_guid;
static guid_t lps0_dsm_guid;
static char lps0_dsm_func_mask;
static char lps0_dsm_func_mask;


/* Device constraint entry structure */
struct lpi_device_info {
	char *name;
	int enabled;
	union acpi_object *package;
};

/* Constraint package structure */
struct lpi_device_constraint {
	int uid;
	int min_dstate;
	int function_states;
};

struct lpi_constraints {
	acpi_handle handle;
	int min_dstate;
};

static struct lpi_constraints *lpi_constraints_table;
static int lpi_constraints_table_size;

static void lpi_device_get_constraints(void)
{
	union acpi_object *out_obj;
	int i;

	out_obj = acpi_evaluate_dsm_typed(lps0_device_handle, &lps0_dsm_guid,
					  1, ACPI_LPS0_GET_DEVICE_CONSTRAINTS,
					  NULL, ACPI_TYPE_PACKAGE);

	acpi_handle_debug(lps0_device_handle, "_DSM function 1 eval %s\n",
			  out_obj ? "successful" : "failed");

	if (!out_obj)
		return;

	lpi_constraints_table = kcalloc(out_obj->package.count,
					sizeof(*lpi_constraints_table),
					GFP_KERNEL);
	if (!lpi_constraints_table)
		goto free_acpi_buffer;

	acpi_handle_debug(lps0_device_handle, "LPI: constraints list begin:\n");

	for (i = 0; i < out_obj->package.count; i++) {
		struct lpi_constraints *constraint;
		acpi_status status;
		union acpi_object *package = &out_obj->package.elements[i];
		struct lpi_device_info info = { };
		int package_count = 0, j;

		if (!package)
			continue;

		for (j = 0; j < package->package.count; ++j) {
			union acpi_object *element =
					&(package->package.elements[j]);

			switch (element->type) {
			case ACPI_TYPE_INTEGER:
				info.enabled = element->integer.value;
				break;
			case ACPI_TYPE_STRING:
				info.name = element->string.pointer;
				break;
			case ACPI_TYPE_PACKAGE:
				package_count = element->package.count;
				info.package = element->package.elements;
				break;
			}
		}

		if (!info.enabled || !info.package || !info.name)
			continue;

		constraint = &lpi_constraints_table[lpi_constraints_table_size];

		status = acpi_get_handle(NULL, info.name, &constraint->handle);
		if (ACPI_FAILURE(status))
			continue;

		acpi_handle_debug(lps0_device_handle,
				  "index:%d Name:%s\n", i, info.name);

		constraint->min_dstate = -1;

		for (j = 0; j < package_count; ++j) {
			union acpi_object *info_obj = &info.package[j];
			union acpi_object *cnstr_pkg;
			union acpi_object *obj;
			struct lpi_device_constraint dev_info;

			switch (info_obj->type) {
			case ACPI_TYPE_INTEGER:
				/* version */
				break;
			case ACPI_TYPE_PACKAGE:
				if (info_obj->package.count < 2)
					break;

				cnstr_pkg = info_obj->package.elements;
				obj = &cnstr_pkg[0];
				dev_info.uid = obj->integer.value;
				obj = &cnstr_pkg[1];
				dev_info.min_dstate = obj->integer.value;

				acpi_handle_debug(lps0_device_handle,
					"uid:%d min_dstate:%s\n",
					dev_info.uid,
					acpi_power_state_string(dev_info.min_dstate));

				constraint->min_dstate = dev_info.min_dstate;
				break;
			}
		}

		if (constraint->min_dstate < 0) {
			acpi_handle_debug(lps0_device_handle,
					  "Incomplete constraint defined\n");
			continue;
		}

		lpi_constraints_table_size++;
	}

	acpi_handle_debug(lps0_device_handle, "LPI: constraints list end\n");

free_acpi_buffer:
	ACPI_FREE(out_obj);
}

static void lpi_check_constraints(void)
{
	int i;

	for (i = 0; i < lpi_constraints_table_size; ++i) {
		struct acpi_device *adev;

		if (acpi_bus_get_device(lpi_constraints_table[i].handle, &adev))
			continue;

		acpi_handle_debug(adev->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(adev->power.state));

		if (!adev->flags.power_manageable) {
			acpi_handle_info(adev->handle, "LPI: Device not power manageble\n");
			continue;
		}

		if (adev->power.state < lpi_constraints_table[i].min_dstate)
			acpi_handle_info(adev->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(adev->power.state));
	}
}

static void acpi_sleep_run_lps0_dsm(unsigned int func)
static void acpi_sleep_run_lps0_dsm(unsigned int func)
{
{
	union acpi_object *out_obj;
	union acpi_object *out_obj;
@@ -714,6 +875,12 @@ static int lps0_device_attach(struct acpi_device *adev,
		if ((bitmask & ACPI_S2IDLE_FUNC_MASK) == ACPI_S2IDLE_FUNC_MASK) {
		if ((bitmask & ACPI_S2IDLE_FUNC_MASK) == ACPI_S2IDLE_FUNC_MASK) {
			lps0_dsm_func_mask = bitmask;
			lps0_dsm_func_mask = bitmask;
			lps0_device_handle = adev->handle;
			lps0_device_handle = adev->handle;
			/*
			 * Use suspend-to-idle by default if the default
			 * suspend mode was not set from the command line.
			 */
			if (mem_sleep_default > PM_SUSPEND_MEM)
				mem_sleep_current = PM_SUSPEND_TO_IDLE;
		}
		}


		acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n",
		acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n",
@@ -723,6 +890,9 @@ static int lps0_device_attach(struct acpi_device *adev,
				  "_DSM function 0 evaluation failed\n");
				  "_DSM function 0 evaluation failed\n");
	}
	}
	ACPI_FREE(out_obj);
	ACPI_FREE(out_obj);

	lpi_device_get_constraints();

	return 0;
	return 0;
}
}


@@ -731,14 +901,14 @@ static struct acpi_scan_handler lps0_handler = {
	.attach = lps0_device_attach,
	.attach = lps0_device_attach,
};
};


static int acpi_freeze_begin(void)
static int acpi_s2idle_begin(void)
{
{
	acpi_scan_lock_acquire();
	acpi_scan_lock_acquire();
	s2idle_in_progress = true;
	s2idle_in_progress = true;
	return 0;
	return 0;
}
}


static int acpi_freeze_prepare(void)
static int acpi_s2idle_prepare(void)
{
{
	if (lps0_device_handle) {
	if (lps0_device_handle) {
		acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF);
		acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF);
@@ -758,8 +928,12 @@ static int acpi_freeze_prepare(void)
	return 0;
	return 0;
}
}


static void acpi_freeze_wake(void)
static void acpi_s2idle_wake(void)
{
{

	if (pm_debug_messages_on)
		lpi_check_constraints();

	/*
	/*
	 * If IRQD_WAKEUP_ARMED is not set for the SCI at this point, it means
	 * If IRQD_WAKEUP_ARMED is not set for the SCI at this point, it means
	 * that the SCI has triggered while suspended, so cancel the wakeup in
	 * that the SCI has triggered while suspended, so cancel the wakeup in
@@ -772,7 +946,7 @@ static void acpi_freeze_wake(void)
	}
	}
}
}


static void acpi_freeze_sync(void)
static void acpi_s2idle_sync(void)
{
{
	/*
	/*
	 * Process all pending events in case there are any wakeup ones.
	 * Process all pending events in case there are any wakeup ones.
@@ -785,7 +959,7 @@ static void acpi_freeze_sync(void)
	s2idle_wakeup = false;
	s2idle_wakeup = false;
}
}


static void acpi_freeze_restore(void)
static void acpi_s2idle_restore(void)
{
{
	if (acpi_sci_irq_valid())
	if (acpi_sci_irq_valid())
		disable_irq_wake(acpi_sci_irq);
		disable_irq_wake(acpi_sci_irq);
@@ -798,19 +972,19 @@ static void acpi_freeze_restore(void)
	}
	}
}
}


static void acpi_freeze_end(void)
static void acpi_s2idle_end(void)
{
{
	s2idle_in_progress = false;
	s2idle_in_progress = false;
	acpi_scan_lock_release();
	acpi_scan_lock_release();
}
}


static const struct platform_freeze_ops acpi_freeze_ops = {
static const struct platform_s2idle_ops acpi_s2idle_ops = {
	.begin = acpi_freeze_begin,
	.begin = acpi_s2idle_begin,
	.prepare = acpi_freeze_prepare,
	.prepare = acpi_s2idle_prepare,
	.wake = acpi_freeze_wake,
	.wake = acpi_s2idle_wake,
	.sync = acpi_freeze_sync,
	.sync = acpi_s2idle_sync,
	.restore = acpi_freeze_restore,
	.restore = acpi_s2idle_restore,
	.end = acpi_freeze_end,
	.end = acpi_s2idle_end,
};
};


static void acpi_sleep_suspend_setup(void)
static void acpi_sleep_suspend_setup(void)
@@ -825,7 +999,7 @@ static void acpi_sleep_suspend_setup(void)
		&acpi_suspend_ops_old : &acpi_suspend_ops);
		&acpi_suspend_ops_old : &acpi_suspend_ops);


	acpi_scan_add_handler(&lps0_handler);
	acpi_scan_add_handler(&lps0_handler);
	freeze_set_ops(&acpi_freeze_ops);
	s2idle_set_ops(&acpi_s2idle_ops);
}
}


#else /* !CONFIG_SUSPEND */
#else /* !CONFIG_SUSPEND */
Loading