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

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

Merge branches 'pm-core', 'pm-sleep' and 'acpi-pm'

* pm-core:
  driver core: Introduce device links reference counting
  PM / wakeirq: Add wakeup name to dedicated wake irqs

* pm-sleep:
  PM / hibernate: Change message when writing to /sys/power/resume
  PM / hibernate: Make passing hibernate offsets more friendly
  PCMCIA / PM: Avoid noirq suspend aborts during suspend-to-idle

* acpi-pm:
  ACPI / PM: Fix keyboard wakeup from suspend-to-idle on ASUS UX331UA
  ACPI / PM: Allow deeper wakeup power states with no _SxD nor _SxW
  ACPI / PM: Reduce LPI constraints logging noise
  ACPI / PM: Do not reconfigure GPEs for suspend-to-idle
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -287,3 +287,17 @@ Description:
		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.

What:		/sys/power/resume_offset
Date:		April 2018
Contact:	Mario Limonciello <mario.limonciello@dell.com>
Description:
		This file is used for telling the kernel an offset into a disk
		to use when hibernating the system such as with a swap file.

		Reads from this file will display the current offset
		the kernel will be using on the next hibernation
		attempt.

		Using this sysfs file will override any values that were
		set using the kernel command line for disk offset.
 No newline at end of file
+9 −1
Original line number Diff line number Diff line
@@ -24,8 +24,16 @@ Some warnings, first.
 * see the FAQ below for details.  (This is not true for more traditional
 * power states like "standby", which normally don't turn USB off.)

Swap partition:
You need to append resume=/dev/your_swap_partition to kernel command
line. Then you suspend by
line or specify it using /sys/power/resume.

Swap file:
If using a swapfile you can also specify a resume offset using
resume_offset=<number> on the kernel command line or specify it
in /sys/power/resume_offset.

After preparing then you suspend by

echo shutdown > /sys/power/disk; echo disk > /sys/power/state

+10 −1
Original line number Diff line number Diff line
@@ -543,6 +543,7 @@ static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev,
	unsigned long long ret;
	int d_min, d_max;
	bool wakeup = false;
	bool has_sxd = false;
	acpi_status status;

	/*
@@ -581,6 +582,10 @@ static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev,
			else
				return -ENODATA;
		}

		if (status == AE_OK)
			has_sxd = true;

		d_min = ret;
		wakeup = device_may_wakeup(dev) && adev->wakeup.flags.valid
			&& adev->wakeup.sleep_state >= target_state;
@@ -599,7 +604,11 @@ static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev,
		method[3] = 'W';
		status = acpi_evaluate_integer(handle, method, NULL, &ret);
		if (status == AE_NOT_FOUND) {
			if (target_state > ACPI_STATE_S0)
			/* No _SxW. In this case, the ACPI spec says that we
			 * must not go into any power state deeper than the
			 * value returned from _SxD.
			 */
			if (has_sxd && target_state > ACPI_STATE_S0)
				d_max = d_min;
		} else if (ACPI_SUCCESS(status) && ret <= ACPI_STATE_D3_COLD) {
			/* Fall back to D3cold if ret is not a valid state. */
+9 −15
Original line number Diff line number Diff line
@@ -851,23 +851,25 @@ static void lpi_check_constraints(void)
	int i;

	for (i = 0; i < lpi_constraints_table_size; ++i) {
		acpi_handle handle = lpi_constraints_table[i].handle;
		struct acpi_device *adev;

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

		acpi_handle_debug(adev->handle,
		acpi_handle_debug(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");
			acpi_handle_info(handle, "LPI: Device not power manageable\n");
			lpi_constraints_table[i].handle = NULL;
			continue;
		}

		if (adev->power.state < lpi_constraints_table[i].min_dstate)
			acpi_handle_info(adev->handle,
			acpi_handle_info(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));
@@ -953,15 +955,8 @@ static int acpi_s2idle_prepare(void)
	if (lps0_device_handle) {
		acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF);
		acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY);
	} else {
		/*
		 * The configuration of GPEs is changed here to avoid spurious
		 * wakeups, but that should not be necessary if this is a
		 * "low-power S0" platform and the low-power S0 _DSM is present.
		 */
		acpi_enable_all_wakeup_gpes();
		acpi_os_wait_events_complete();
	}

	if (acpi_sci_irq_valid())
		enable_irq_wake(acpi_sci_irq);

@@ -994,8 +989,9 @@ static void acpi_s2idle_sync(void)
	 * The EC driver uses the system workqueue and an additional special
	 * one, so those need to be flushed too.
	 */
	acpi_os_wait_events_complete();	/* synchronize SCI IRQ handling */
	acpi_ec_flush_work();
	acpi_os_wait_events_complete();
	acpi_os_wait_events_complete();	/* synchronize Notify handling */
	s2idle_wakeup = false;
}

@@ -1007,8 +1003,6 @@ static void acpi_s2idle_restore(void)
	if (lps0_device_handle) {
		acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT);
		acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON);
	} else {
		acpi_enable_all_runtime_gpes();
	}
}

+17 −8
Original line number Diff line number Diff line
@@ -196,8 +196,10 @@ struct device_link *device_link_add(struct device *consumer,
	}

	list_for_each_entry(link, &supplier->links.consumers, s_node)
		if (link->consumer == consumer)
		if (link->consumer == consumer) {
			kref_get(&link->kref);
			goto out;
		}

	link = kzalloc(sizeof(*link), GFP_KERNEL);
	if (!link)
@@ -222,6 +224,7 @@ struct device_link *device_link_add(struct device *consumer,
	link->consumer = consumer;
	INIT_LIST_HEAD(&link->c_node);
	link->flags = flags;
	kref_init(&link->kref);

	/* Determine the initial link state. */
	if (flags & DL_FLAG_STATELESS) {
@@ -292,8 +295,10 @@ static void __device_link_free_srcu(struct rcu_head *rhead)
	device_link_free(container_of(rhead, struct device_link, rcu_head));
}

static void __device_link_del(struct device_link *link)
static void __device_link_del(struct kref *kref)
{
	struct device_link *link = container_of(kref, struct device_link, kref);

	dev_info(link->consumer, "Dropping the link to %s\n",
		 dev_name(link->supplier));

@@ -305,8 +310,10 @@ static void __device_link_del(struct device_link *link)
	call_srcu(&device_links_srcu, &link->rcu_head, __device_link_free_srcu);
}
#else /* !CONFIG_SRCU */
static void __device_link_del(struct device_link *link)
static void __device_link_del(struct kref *kref)
{
	struct device_link *link = container_of(kref, struct device_link, kref);

	dev_info(link->consumer, "Dropping the link to %s\n",
		 dev_name(link->supplier));

@@ -324,13 +331,15 @@ static void __device_link_del(struct device_link *link)
 * @link: Device link to delete.
 *
 * The caller must ensure proper synchronization of this function with runtime
 * PM.
 * PM.  If the link was added multiple times, it needs to be deleted as often.
 * Care is required for hotplugged devices:  Their links are purged on removal
 * and calling device_link_del() is then no longer allowed.
 */
void device_link_del(struct device_link *link)
{
	device_links_write_lock();
	device_pm_lock();
	__device_link_del(link);
	kref_put(&link->kref, __device_link_del);
	device_pm_unlock();
	device_links_write_unlock();
}
@@ -444,7 +453,7 @@ static void __device_links_no_driver(struct device *dev)
			continue;

		if (link->flags & DL_FLAG_AUTOREMOVE)
			__device_link_del(link);
			kref_put(&link->kref, __device_link_del);
		else if (link->status != DL_STATE_SUPPLIER_UNBIND)
			WRITE_ONCE(link->status, DL_STATE_AVAILABLE);
	}
@@ -597,13 +606,13 @@ static void device_links_purge(struct device *dev)

	list_for_each_entry_safe_reverse(link, ln, &dev->links.suppliers, c_node) {
		WARN_ON(link->status == DL_STATE_ACTIVE);
		__device_link_del(link);
		__device_link_del(&link->kref);
	}

	list_for_each_entry_safe_reverse(link, ln, &dev->links.consumers, s_node) {
		WARN_ON(link->status != DL_STATE_DORMANT &&
			link->status != DL_STATE_NONE);
		__device_link_del(link);
		__device_link_del(&link->kref);
	}

	device_links_write_unlock();
Loading