linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] Suspend block api (version 7)
@ 2010-05-14  4:11 Arve Hjønnevåg
  2010-05-14  4:11 ` [PATCH 1/8] PM: Add suspend block api Arve Hjønnevåg
                   ` (2 more replies)
  0 siblings, 3 replies; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-14  4:11 UTC (permalink / raw)
  To: linux-pm, linux-kernel; +Cc: Rafael J. Wysocki

This patch series adds a suspend-block api that provides the same
functionality as the android wakelock api. This version has some
changes from, or requested by, Rafael. The most notable changes are:
- DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
  for statically allocated suspend blockers. 
- suspend_blocker_destroy is now called suspend_blocker_unregister
- The user space mandatory _INIT ioctl has been replaced with an
  optional _SET_NAME ioctl.

I kept the ack and reviewed by tags on two of the patches even though
there were a few cosmetic changes.

--
Arve Hjønnevåg <arve@android.com>


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH 1/8] PM: Add suspend block api.
  2010-05-14  4:11 [PATCH 0/8] Suspend block api (version 7) Arve Hjønnevåg
@ 2010-05-14  4:11 ` Arve Hjønnevåg
  2010-05-14  4:11   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
  2010-05-18 13:11   ` [PATCH 1/8] PM: Add suspend block api Pavel Machek
  2010-05-14 21:08 ` [PATCH 0/8] Suspend block api (version 7) Rafael J. Wysocki
  2010-05-16 19:42 ` Rafael J. Wysocki
  2 siblings, 2 replies; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-14  4:11 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Rafael J. Wysocki, Arve Hjønnevåg, Len Brown,
	Pavel Machek, Randy Dunlap, Andrew Morton, Andi Kleen,
	Cornelia Huck, Tejun Heo, Jesse Barnes, Magnus Damm,
	Nigel Cunningham, Alan Stern, Ming Lei, Wu Fengguang,
	Maxim Levitsky, linux-doc

Adds /sys/power/policy that selects the behaviour of /sys/power/state.
After setting the policy to opportunistic, writes to /sys/power/state
become non-blocking requests that specify which suspend state to enter
when no suspend blockers are active. A special state, "on", stops the
process by activating the "main" suspend blocker.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 Documentation/power/opportunistic-suspend.txt |  129 +++++++++++
 include/linux/suspend.h                       |    1 +
 include/linux/suspend_blocker.h               |   74 +++++++
 kernel/power/Kconfig                          |   16 ++
 kernel/power/Makefile                         |    1 +
 kernel/power/main.c                           |  128 +++++++++++-
 kernel/power/opportunistic_suspend.c          |  284 +++++++++++++++++++++++++
 kernel/power/power.h                          |    9 +
 kernel/power/suspend.c                        |    3 +-
 9 files changed, 637 insertions(+), 8 deletions(-)
 create mode 100644 Documentation/power/opportunistic-suspend.txt
 create mode 100755 include/linux/suspend_blocker.h
 create mode 100644 kernel/power/opportunistic_suspend.c

diff --git a/Documentation/power/opportunistic-suspend.txt b/Documentation/power/opportunistic-suspend.txt
new file mode 100644
index 0000000..4bee7bc
--- /dev/null
+++ b/Documentation/power/opportunistic-suspend.txt
@@ -0,0 +1,129 @@
+Opportunistic Suspend
+=====================
+
+Opportunistic suspend is a feature allowing the system to be suspended (ie. put
+into one of the available sleep states) automatically whenever it is regarded
+as idle.  The suspend blockers framework described below is used to determine
+when that happens.
+
+The /sys/power/policy sysfs attribute is used to switch the system between the
+opportunistic and "forced" suspend behavior, where in the latter case the
+system is only suspended if a specific value, corresponding to one of the
+available system sleep states, is written into /sys/power/state.  However, in
+the former, opportunistic, case the system is put into the sleep state
+corresponding to the value written to /sys/power/state whenever there are no
+active suspend blockers. The default policy is "forced". Also, suspend blockers
+do not affect sleep states entered from idle.
+
+When the policy is "opportunisic", there is a special value, "on", that can be
+written to /sys/power/state. This will block the automatic sleep request, as if
+a suspend blocker was used by a device driver. This way the opportunistic
+suspend may be blocked by user space whithout switching back to the "forced"
+mode.
+
+A suspend blocker is an object used to inform the PM subsystem when the system
+can or cannot be suspended in the "opportunistic" mode (the "forced" mode
+ignores suspend blockers).  To use it, a device driver creates a struct
+suspend_blocker that must be initialized with suspend_blocker_init(). Before
+freeing the suspend_blocker structure or its name, suspend_blocker_unregister()
+must be called on it.
+
+A suspend blocker is activated using suspend_block(), which prevents the PM
+subsystem from putting the system into the requested sleep state in the
+"opportunistic" mode until the suspend blocker is deactivated with
+suspend_unblock(). Multiple suspend blockers may be active simultaneously, and
+the system will not suspend as long as at least one of them is active.
+
+If opportunistic suspend is already in progress when suspend_block() is called,
+it will abort the suspend, unless suspend_ops->enter has already been
+executed. If suspend is aborted this way, the system is usually not fully
+operational at that point. The suspend callbacks of some drivers may still be
+running and it usually takes time to restore the system to the fully operational
+state.
+
+Here's an example showing how a cell phone or other embedded system can handle
+keystrokes (or other input events) in the presence of suspend blockers. Use
+set_irq_wake or a platform specific API to make sure the keypad interrupt wakes
+up the cpu. Once the keypad driver has resumed, the sequence of events can look
+like this:
+
+- The Keypad driver gets an interrupt. It then calls suspend_block on the
+  keypad-scan suspend_blocker and starts scanning the keypad matrix.
+- The keypad-scan code detects a key change and reports it to the input-event
+  driver.
+- The input-event driver sees the key change, enqueues an event, and calls
+  suspend_block on the input-event-queue suspend_blocker.
+- The keypad-scan code detects that no keys are held and calls suspend_unblock
+  on the keypad-scan suspend_blocker.
+- The user-space input-event thread returns from select/poll, calls
+  suspend_block on the process-input-events suspend_blocker and then calls read
+  on the input-event device.
+- The input-event driver dequeues the key-event and, since the queue is now
+  empty, it calls suspend_unblock on the input-event-queue suspend_blocker.
+- The user-space input-event thread returns from read. If it determines that
+  the key should be ignored, it calls suspend_unblock on the
+  process_input_events suspend_blocker and then calls select or poll. The
+  system will automatically suspend again, since now no suspend blockers are
+  active.
+
+If the key that was pressed instead should preform a simple action (for example,
+adjusting the volume), this action can be performed right before calling
+suspend_unblock on the process_input_events suspend_blocker. However, if the key
+triggers a longer-running action, that action needs its own suspend_blocker and
+suspend_block must be called on that suspend blocker before calling
+suspend_unblock on the process_input_events suspend_blocker.
+
+                 Key pressed   Key released
+                     |             |
+keypad-scan          ++++++++++++++++++
+input-event-queue        +++          +++
+process-input-events       +++          +++
+
+
+Driver API
+==========
+
+A driver can use the suspend block API by adding a suspend_blocker variable to
+its state and calling suspend_blocker_init(). For instance:
+
+struct state {
+	struct suspend_blocker suspend_blocker;
+}
+
+init() {
+	suspend_blocker_init(&state->suspend_blocker, name);
+}
+
+If the suspend_blocker variable is allocated statically,
+DEFINE_SUSPEND_BLOCKER() should be used to initialize it, for example:
+
+static DEFINE_SUSPEND_BLOCKER(blocker, name);
+
+and suspend_blocker_register(&blocker) has to be called to make the suspend
+blocker usable.
+
+Before freeing the memory in which a suspend_blocker variable is located,
+suspend_blocker_unregister() must be called, for instance:
+
+uninit() {
+	suspend_blocker_unregister(&state->suspend_blocker);
+}
+
+When the driver determines that it needs to run (usually in an interrupt
+handler) it calls suspend_block():
+
+	suspend_block(&state->suspend_blocker);
+
+When it no longer needs to run it calls suspend_unblock():
+
+	suspend_unblock(&state->suspend_blocker);
+
+Calling suspend_block() when the suspend blocker is active or suspend_unblock()
+when it is not active has no effect (i.e., these functions don't nest). This
+allows drivers to update their state and call suspend suspend_block() or
+suspend_unblock() based on the result. For instance:
+
+if (list_empty(&state->pending_work))
+	suspend_unblock(&state->suspend_blocker);
+else
+	suspend_block(&state->suspend_blocker);
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 5e781d8..07023d3 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -6,6 +6,7 @@
 #include <linux/init.h>
 #include <linux/pm.h>
 #include <linux/mm.h>
+#include <linux/suspend_blocker.h>
 #include <asm/errno.h>
 
 #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE)
diff --git a/include/linux/suspend_blocker.h b/include/linux/suspend_blocker.h
new file mode 100755
index 0000000..8788302
--- /dev/null
+++ b/include/linux/suspend_blocker.h
@@ -0,0 +1,74 @@
+/* include/linux/suspend_blocker.h
+ *
+ * Copyright (C) 2007-2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_SUSPEND_BLOCKER_H
+#define _LINUX_SUSPEND_BLOCKER_H
+
+#include <linux/list.h>
+
+/**
+ * struct suspend_blocker - the basic suspend_blocker structure
+ * @link: List entry for active or inactive list.
+ * @flags: Tracks initialized and active state.
+ * @name: Suspend blocker name used for debugging.
+ *
+ * When a suspend_blocker is active it prevents the system from entering
+ * opportunistic suspend.
+ *
+ * The suspend_blocker structure must be initialized by suspend_blocker_init()
+ */
+struct suspend_blocker {
+#ifdef CONFIG_OPPORTUNISTIC_SUSPEND
+	struct list_head link;
+	int flags;
+	const char *name;
+#endif
+};
+
+#ifdef CONFIG_OPPORTUNISTIC_SUSPEND
+#define __SUSPEND_BLOCKER_INITIALIZER(blocker_name) \
+	{ .name = #blocker_name, }
+
+#define DEFINE_SUSPEND_BLOCKER(blocker, name) \
+	struct suspend_blocker blocker = __SUSPEND_BLOCKER_INITIALIZER(name)
+
+extern void suspend_blocker_register(struct suspend_blocker *blocker);
+extern void suspend_blocker_init(struct suspend_blocker *blocker,
+				 const char *name);
+extern void suspend_blocker_unregister(struct suspend_blocker *blocker);
+extern void suspend_block(struct suspend_blocker *blocker);
+extern void suspend_unblock(struct suspend_blocker *blocker);
+extern bool suspend_blocker_is_active(struct suspend_blocker *blocker);
+extern bool suspend_is_blocked(void);
+
+#else
+
+#define DEFINE_SUSPEND_BLOCKER(blocker, name) \
+	struct suspend_blocker blocker
+
+static inline void suspend_blocker_register(struct suspend_blocker *bl) {}
+static inline void suspend_blocker_init(struct suspend_blocker *bl,
+					const char *n) {}
+static inline void suspend_blocker_unregister(struct suspend_blocker *bl) {}
+static inline void suspend_block(struct suspend_blocker *bl) {}
+static inline void suspend_unblock(struct suspend_blocker *bl) {}
+static inline bool suspend_blocker_is_active(struct suspend_blocker *bl)
+{
+	return false;
+}
+static inline bool suspend_is_blocked(void) { return false; }
+#endif
+
+#endif
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 5c36ea9..6d11a45 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -130,6 +130,22 @@ config SUSPEND_FREEZER
 
 	  Turning OFF this setting is NOT recommended! If in doubt, say Y.
 
+config OPPORTUNISTIC_SUSPEND
+	bool "Opportunistic suspend"
+	depends on SUSPEND
+	select RTC_LIB
+	default n
+	---help---
+	  Opportunistic sleep support.  Allows the system to be put into a sleep
+	  state opportunistically, if it doesn't do any useful work at the
+	  moment. The PM subsystem is switched into this mode of operation by
+	  writing "opportunistic" into /sys/power/policy, while writing
+	  "forced" to this file turns the opportunistic suspend feature off.
+	  In the "opportunistic" mode suspend blockers are used to determine
+	  when to suspend the system and the value written to /sys/power/state
+	  determines the sleep state the system will be put into when there are
+	  no active suspend blockers.
+
 config HIBERNATION_NVS
 	bool
 
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 4319181..95d8e6d 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_PM)		+= main.o
 obj-$(CONFIG_PM_SLEEP)		+= console.o
 obj-$(CONFIG_FREEZER)		+= process.o
 obj-$(CONFIG_SUSPEND)		+= suspend.o
+obj-$(CONFIG_OPPORTUNISTIC_SUSPEND)	+= opportunistic_suspend.o
 obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
 obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o
 obj-$(CONFIG_HIBERNATION_NVS)	+= hibernate_nvs.o
diff --git a/kernel/power/main.c b/kernel/power/main.c
index b58800b..afbb4dd 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -20,6 +20,58 @@ DEFINE_MUTEX(pm_mutex);
 unsigned int pm_flags;
 EXPORT_SYMBOL(pm_flags);
 
+#ifdef CONFIG_OPPORTUNISTIC_SUSPEND
+struct pm_policy {
+	const char *name;
+	bool (*valid_state)(suspend_state_t state);
+	int (*set_state)(suspend_state_t state);
+};
+
+static struct pm_policy policies[] = {
+	{
+		.name		= "forced",
+		.valid_state	= valid_state,
+		.set_state	= enter_state,
+	},
+	{
+		.name		= "opportunistic",
+		.valid_state	= opportunistic_suspend_valid_state,
+		.set_state	= opportunistic_suspend_state,
+	},
+};
+
+static int policy;
+
+static inline bool hibernation_supported(void)
+{
+	return !strncmp(policies[policy].name, "forced", 6);
+}
+
+static inline bool pm_state_valid(int state_idx)
+{
+	return pm_states[state_idx] && policies[policy].valid_state(state_idx);
+}
+
+static inline int pm_enter_state(int state_idx)
+{
+	return policies[policy].set_state(state_idx);
+}
+
+#else
+
+static inline bool hibernation_supported(void) { return true; }
+
+static inline bool pm_state_valid(int state_idx)
+{
+	return pm_states[state_idx] && valid_state(state_idx);
+}
+
+static inline int pm_enter_state(int state_idx)
+{
+	return enter_state(state_idx);
+}
+#endif /* CONFIG_OPPORTUNISTIC_SUSPEND */
+
 #ifdef CONFIG_PM_SLEEP
 
 /* Routines for PM-transition notifications */
@@ -146,6 +198,12 @@ struct kobject *power_kobj;
  *
  *	store() accepts one of those strings, translates it into the 
  *	proper enumerated value, and initiates a suspend transition.
+ *
+ *	If policy is set to opportunistic, store() does not block until the
+ *	system resumes, and it will try to re-enter the state until another
+ *	state is requested. Suspend blockers are respected and the requested
+ *	state will only be entered when no suspend blockers are active.
+ *	Write "on" to disable.
  */
 static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
 			  char *buf)
@@ -155,12 +213,13 @@ static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
 	int i;
 
 	for (i = 0; i < PM_SUSPEND_MAX; i++) {
-		if (pm_states[i] && valid_state(i))
+		if (pm_state_valid(i))
 			s += sprintf(s,"%s ", pm_states[i]);
 	}
 #endif
 #ifdef CONFIG_HIBERNATION
-	s += sprintf(s, "%s\n", "disk");
+	if (hibernation_supported())
+		s += sprintf(s, "%s\n", "disk");
 #else
 	if (s != buf)
 		/* convert the last space to a newline */
@@ -173,7 +232,7 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
 			   const char *buf, size_t n)
 {
 #ifdef CONFIG_SUSPEND
-	suspend_state_t state = PM_SUSPEND_STANDBY;
+	suspend_state_t state = PM_SUSPEND_ON;
 	const char * const *s;
 #endif
 	char *p;
@@ -185,8 +244,9 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
 
 	/* First, check if we are requested to hibernate */
 	if (len == 4 && !strncmp(buf, "disk", len)) {
-		error = hibernate();
-  goto Exit;
+		if (hibernation_supported())
+			error = hibernate();
+		goto Exit;
 	}
 
 #ifdef CONFIG_SUSPEND
@@ -195,7 +255,7 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
 			break;
 	}
 	if (state < PM_SUSPEND_MAX && *s)
-		error = enter_state(state);
+		error = pm_enter_state(state);
 #endif
 
  Exit:
@@ -204,6 +264,56 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
 
 power_attr(state);
 
+#ifdef CONFIG_OPPORTUNISTIC_SUSPEND
+/**
+ *	policy - set policy for state
+ */
+static ssize_t policy_show(struct kobject *kobj,
+			   struct kobj_attribute *attr, char *buf)
+{
+	char *s = buf;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(policies); i++) {
+		if (i == policy)
+			s += sprintf(s, "[%s] ", policies[i].name);
+		else
+			s += sprintf(s, "%s ", policies[i].name);
+	}
+	if (s != buf)
+		/* convert the last space to a newline */
+		*(s-1) = '\n';
+	return (s - buf);
+}
+
+static ssize_t policy_store(struct kobject *kobj,
+			    struct kobj_attribute *attr,
+			    const char *buf, size_t n)
+{
+	const char *s;
+	char *p;
+	int len;
+	int i;
+
+	p = memchr(buf, '\n', n);
+	len = p ? p - buf : n;
+
+	for (i = 0; i < ARRAY_SIZE(policies); i++) {
+		s = policies[i].name;
+		if (s && len == strlen(s) && !strncmp(buf, s, len)) {
+			mutex_lock(&pm_mutex);
+			policies[policy].set_state(PM_SUSPEND_ON);
+			policy = i;
+			mutex_unlock(&pm_mutex);
+			return n;
+		}
+	}
+	return -EINVAL;
+}
+
+power_attr(policy);
+#endif /* CONFIG_OPPORTUNISTIC_SUSPEND */
+
 #ifdef CONFIG_PM_TRACE
 int pm_trace_enabled;
 
@@ -236,6 +346,9 @@ static struct attribute * g[] = {
 #endif
 #ifdef CONFIG_PM_SLEEP
 	&pm_async_attr.attr,
+#ifdef CONFIG_OPPORTUNISTIC_SUSPEND
+	&policy_attr.attr,
+#endif
 #ifdef CONFIG_PM_DEBUG
 	&pm_test_attr.attr,
 #endif
@@ -247,7 +360,7 @@ static struct attribute_group attr_group = {
 	.attrs = g,
 };
 
-#ifdef CONFIG_PM_RUNTIME
+#if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_OPPORTUNISTIC_SUSPEND)
 struct workqueue_struct *pm_wq;
 EXPORT_SYMBOL_GPL(pm_wq);
 
@@ -266,6 +379,7 @@ static int __init pm_init(void)
 	int error = pm_start_workqueue();
 	if (error)
 		return error;
+	opportunistic_suspend_init();
 	power_kobj = kobject_create_and_add("power", NULL);
 	if (!power_kobj)
 		return -ENOMEM;
diff --git a/kernel/power/opportunistic_suspend.c b/kernel/power/opportunistic_suspend.c
new file mode 100644
index 0000000..acc1651
--- /dev/null
+++ b/kernel/power/opportunistic_suspend.c
@@ -0,0 +1,284 @@
+/*
+ * kernel/power/opportunistic_suspend.c
+ *
+ * Copyright (C) 2005-2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/suspend.h>
+
+#include "power.h"
+
+extern struct workqueue_struct *pm_wq;
+
+enum {
+	DEBUG_EXIT_SUSPEND = 1U << 0,
+	DEBUG_WAKEUP = 1U << 1,
+	DEBUG_USER_STATE = 1U << 2,
+	DEBUG_SUSPEND = 1U << 3,
+	DEBUG_SUSPEND_BLOCKER = 1U << 4,
+};
+static int debug_mask = DEBUG_EXIT_SUSPEND | DEBUG_WAKEUP | DEBUG_USER_STATE;
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define SB_INITIALIZED            (1U << 8)
+#define SB_ACTIVE                 (1U << 9)
+
+DEFINE_SUSPEND_BLOCKER(main_suspend_blocker, main);
+
+static DEFINE_SPINLOCK(list_lock);
+static DEFINE_SPINLOCK(state_lock);
+static LIST_HEAD(inactive_blockers);
+static LIST_HEAD(active_blockers);
+static int current_event_num;
+static suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
+static bool enable_suspend_blockers;
+
+#define pr_info_time(fmt, args...) \
+	do { \
+		struct timespec ts; \
+		struct rtc_time tm; \
+		getnstimeofday(&ts); \
+		rtc_time_to_tm(ts.tv_sec, &tm); \
+		pr_info(fmt "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n" , \
+			args, \
+			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, \
+			tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); \
+	} while (0);
+
+static void print_active_suspend_blockers(void)
+{
+	struct suspend_blocker *blocker;
+
+	list_for_each_entry(blocker, &active_blockers, link)
+		pr_info("PM: Active suspend blocker %s\n", blocker->name);
+}
+
+/**
+ * suspend_is_blocked - Check if there are active suspend blockers.
+ *
+ * Return true if suspend blockers are enabled and there are active suspend
+ * blockers, in which case the system cannot be put to sleep opportunistically.
+ */
+bool suspend_is_blocked(void)
+{
+	return enable_suspend_blockers && !list_empty(&active_blockers);
+}
+
+static void suspend_worker(struct work_struct *work)
+{
+	int ret;
+	int entry_event_num;
+
+	enable_suspend_blockers = true;
+
+	if (suspend_is_blocked()) {
+		if (debug_mask & DEBUG_SUSPEND)
+			pr_info("PM: Automatic suspend aborted\n");
+		goto abort;
+	}
+
+	entry_event_num = current_event_num;
+
+	if (debug_mask & DEBUG_SUSPEND)
+		pr_info("PM: Automatic suspend\n");
+
+	ret = pm_suspend(requested_suspend_state);
+
+	if (debug_mask & DEBUG_EXIT_SUSPEND)
+		pr_info_time("PM: Automatic suspend exit, ret = %d ", ret);
+
+	if (current_event_num == entry_event_num) {
+		if (debug_mask & DEBUG_SUSPEND)
+			pr_info("PM: pm_suspend() returned with no event\n");
+		queue_work(pm_wq, work);
+	}
+
+abort:
+	enable_suspend_blockers = false;
+}
+static DECLARE_WORK(suspend_work, suspend_worker);
+
+/**
+ * suspend_blocker_register - Prepare a suspend blocker for being used.
+ * @blocker: Suspend blocker to handle.
+ *
+ * The suspend blocker struct and name must not be freed before calling
+ * suspend_blocker_unregister().
+ */
+void suspend_blocker_register(struct suspend_blocker *blocker)
+{
+	unsigned long irqflags = 0;
+
+	WARN_ON(!blocker->name);
+
+	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
+		pr_info("%s: Registering %s\n", __func__, blocker->name);
+
+	blocker->flags = SB_INITIALIZED;
+	INIT_LIST_HEAD(&blocker->link);
+
+	spin_lock_irqsave(&list_lock, irqflags);
+	list_add(&blocker->link, &inactive_blockers);
+	spin_unlock_irqrestore(&list_lock, irqflags);
+}
+EXPORT_SYMBOL(suspend_blocker_register);
+
+/**
+ * suspend_blocker_init - Initialize a suspend blocker's name and register it.
+ * @blocker: Suspend blocker to initialize.
+ * @name:    The name of the suspend blocker to show in debug messages.
+ *
+ * The suspend blocker struct and name must not be freed before calling
+ * suspend_blocker_unregister().
+ */
+void suspend_blocker_init(struct suspend_blocker *blocker, const char *name)
+{
+	blocker->name = name;
+	suspend_blocker_register(blocker);
+}
+EXPORT_SYMBOL(suspend_blocker_init);
+
+/**
+ * suspend_blocker_unregister - Unregister a suspend blocker.
+ * @blocker: Suspend blocker to handle.
+ */
+void suspend_blocker_unregister(struct suspend_blocker *blocker)
+{
+	unsigned long irqflags;
+
+	if (WARN_ON(!(blocker->flags & SB_INITIALIZED)))
+		return;
+
+	spin_lock_irqsave(&list_lock, irqflags);
+	blocker->flags &= ~SB_INITIALIZED;
+	list_del(&blocker->link);
+	if ((blocker->flags & SB_ACTIVE) && list_empty(&active_blockers))
+		queue_work(pm_wq, &suspend_work);
+	spin_unlock_irqrestore(&list_lock, irqflags);
+
+	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
+		pr_info("%s: Unregistered %s\n", __func__, blocker->name);
+}
+EXPORT_SYMBOL(suspend_blocker_unregister);
+
+/**
+ * suspend_block - Block system suspend.
+ * @blocker: Suspend blocker to use.
+ *
+ * It is safe to call this function from interrupt context.
+ */
+void suspend_block(struct suspend_blocker *blocker)
+{
+	unsigned long irqflags;
+
+	if (WARN_ON(!(blocker->flags & SB_INITIALIZED)))
+		return;
+
+	spin_lock_irqsave(&list_lock, irqflags);
+
+	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
+		pr_info("%s: %s\n", __func__, blocker->name);
+
+	blocker->flags |= SB_ACTIVE;
+	list_move(&blocker->link, &active_blockers);
+
+	current_event_num++;
+
+	spin_unlock_irqrestore(&list_lock, irqflags);
+}
+EXPORT_SYMBOL(suspend_block);
+
+/**
+ * suspend_unblock - Allow system suspend to happen.
+ * @blocker: Suspend blocker to unblock.
+ *
+ * If no other suspend blockers are active, schedule suspend of the system.
+ *
+ * It is safe to call this function from interrupt context.
+ */
+void suspend_unblock(struct suspend_blocker *blocker)
+{
+	unsigned long irqflags;
+
+	if (WARN_ON(!(blocker->flags & SB_INITIALIZED)))
+		return;
+
+	spin_lock_irqsave(&list_lock, irqflags);
+
+	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
+		pr_info("%s: %s\n", __func__, blocker->name);
+
+	list_move(&blocker->link, &inactive_blockers);
+	if ((blocker->flags & SB_ACTIVE) && list_empty(&active_blockers))
+		queue_work(pm_wq, &suspend_work);
+	blocker->flags &= ~(SB_ACTIVE);
+
+	if ((debug_mask & DEBUG_SUSPEND) && blocker == &main_suspend_blocker)
+		print_active_suspend_blockers();
+
+	spin_unlock_irqrestore(&list_lock, irqflags);
+}
+EXPORT_SYMBOL(suspend_unblock);
+
+/**
+ * suspend_blocker_is_active - Test if a suspend blocker is blocking suspend
+ * @blocker: Suspend blocker to check.
+ *
+ * Returns true if the suspend_blocker is currently active.
+ */
+bool suspend_blocker_is_active(struct suspend_blocker *blocker)
+{
+	WARN_ON(!(blocker->flags & SB_INITIALIZED));
+
+	return !!(blocker->flags & SB_ACTIVE);
+}
+EXPORT_SYMBOL(suspend_blocker_is_active);
+
+bool opportunistic_suspend_valid_state(suspend_state_t state)
+{
+	return (state == PM_SUSPEND_ON) || valid_state(state);
+}
+
+int opportunistic_suspend_state(suspend_state_t state)
+{
+	unsigned long irqflags;
+
+	if (!opportunistic_suspend_valid_state(state))
+		return -ENODEV;
+
+	spin_lock_irqsave(&state_lock, irqflags);
+
+	if (debug_mask & DEBUG_USER_STATE)
+		pr_info_time("%s: %s (%d->%d) at %lld ", __func__,
+			     state != PM_SUSPEND_ON ? "sleep" : "wakeup",
+			     requested_suspend_state, state,
+			     ktime_to_ns(ktime_get()));
+
+	requested_suspend_state = state;
+	if (state == PM_SUSPEND_ON)
+		suspend_block(&main_suspend_blocker);
+	else
+		suspend_unblock(&main_suspend_blocker);
+
+	spin_unlock_irqrestore(&state_lock, irqflags);
+
+	return 0;
+}
+
+void __init opportunistic_suspend_init(void)
+{
+	suspend_blocker_register(&main_suspend_blocker);
+	suspend_block(&main_suspend_blocker);
+}
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 46c5a26..2e9cfd5 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -236,3 +236,12 @@ static inline void suspend_thaw_processes(void)
 {
 }
 #endif
+
+#ifdef CONFIG_OPPORTUNISTIC_SUSPEND
+/* kernel/power/opportunistic_suspend.c */
+extern int opportunistic_suspend_state(suspend_state_t state);
+extern bool opportunistic_suspend_valid_state(suspend_state_t state);
+extern void __init opportunistic_suspend_init(void);
+#else
+static inline void opportunistic_suspend_init(void) {}
+#endif
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 56e7dbb..9eb3876 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -20,6 +20,7 @@
 #include "power.h"
 
 const char *const pm_states[PM_SUSPEND_MAX] = {
+	[PM_SUSPEND_ON]		= "on",
 	[PM_SUSPEND_STANDBY]	= "standby",
 	[PM_SUSPEND_MEM]	= "mem",
 };
@@ -157,7 +158,7 @@ static int suspend_enter(suspend_state_t state)
 
 	error = sysdev_suspend(PMSG_SUSPEND);
 	if (!error) {
-		if (!suspend_test(TEST_CORE))
+		if (!suspend_is_blocked() && !suspend_test(TEST_CORE))
 			error = suspend_ops->enter(state);
 		sysdev_resume();
 	}
-- 
1.6.5.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space
  2010-05-14  4:11 ` [PATCH 1/8] PM: Add suspend block api Arve Hjønnevåg
@ 2010-05-14  4:11   ` Arve Hjønnevåg
  2010-05-14  4:11     ` [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active Arve Hjønnevåg
  2010-05-18 13:11   ` [PATCH 1/8] PM: Add suspend block api Pavel Machek
  1 sibling, 1 reply; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-14  4:11 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Rafael J. Wysocki, Arve Hjønnevåg, Randy Dunlap,
	Andrew Morton, Ryusuke Konishi, Jim Collar, Greg Kroah-Hartman,
	Avi Kivity, Len Brown, Pavel Machek, Magnus Damm, Cornelia Huck,
	Nigel Cunningham, linux-doc

Add a misc device, "suspend_blocker", that allows user-space processes
to block auto suspend. The device has ioctls to create a suspend_blocker,
and to block and unblock suspend. To delete the suspend_blocker, close
the device.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 Documentation/ioctl/ioctl-number.txt          |    3 +-
 Documentation/power/opportunistic-suspend.txt |   27 +++++
 include/linux/suspend_ioctls.h                |    4 +
 kernel/power/Kconfig                          |    7 ++
 kernel/power/Makefile                         |    1 +
 kernel/power/user_suspend_blocker.c           |  143 +++++++++++++++++++++++++
 6 files changed, 184 insertions(+), 1 deletions(-)
 create mode 100644 kernel/power/user_suspend_blocker.c

diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index dd5806f..e2458f7 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -254,7 +254,8 @@ Code  Seq#(hex)	Include File		Comments
 'q'	80-FF	linux/telephony.h	Internet PhoneJACK, Internet LineJACK
 		linux/ixjuser.h		<http://www.quicknet.net>
 'r'	00-1F	linux/msdos_fs.h and fs/fat/dir.c
-'s'	all	linux/cdk.h
+'s'	all	linux/cdk.h	conflict!
+'s'	all	linux/suspend_block_dev.h	conflict!
 't'	00-7F	linux/if_ppp.h
 't'	80-8F	linux/isdn_ppp.h
 't'	90	linux/toshiba.h
diff --git a/Documentation/power/opportunistic-suspend.txt b/Documentation/power/opportunistic-suspend.txt
index 4bee7bc..93f4c24 100644
--- a/Documentation/power/opportunistic-suspend.txt
+++ b/Documentation/power/opportunistic-suspend.txt
@@ -127,3 +127,30 @@ if (list_empty(&state->pending_work))
 	suspend_unblock(&state->suspend_blocker);
 else
 	suspend_block(&state->suspend_blocker);
+
+User space API
+==============
+
+To create a suspend blocker from user space, open the suspend_blocker special
+device file:
+
+    fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
+
+then optionally call:
+
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_SET_NAME(strlen(name)), name);
+
+To activate the suspend blocker call:
+
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
+
+To deactivate it call:
+
+    ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
+
+To destroy the suspend blocker, close the device:
+
+    close(fd);
+
+If the first ioctl called is not SUSPEND_BLOCKER_IOCTL_SET_NAME the suspend
+blocker will get the default name "(userspace)".
diff --git a/include/linux/suspend_ioctls.h b/include/linux/suspend_ioctls.h
index 0b30382..b95a6b2 100644
--- a/include/linux/suspend_ioctls.h
+++ b/include/linux/suspend_ioctls.h
@@ -30,4 +30,8 @@ struct resume_swap_area {
 #define SNAPSHOT_ALLOC_SWAP_PAGE	_IOR(SNAPSHOT_IOC_MAGIC, 20, __kernel_loff_t)
 #define SNAPSHOT_IOC_MAXNR	20
 
+#define SUSPEND_BLOCKER_IOCTL_SET_NAME(len)	_IOC(_IOC_WRITE, 's', 0, len)
+#define SUSPEND_BLOCKER_IOCTL_BLOCK		_IO('s', 1)
+#define SUSPEND_BLOCKER_IOCTL_UNBLOCK		_IO('s', 2)
+
 #endif /* _LINUX_SUSPEND_IOCTLS_H */
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 6d11a45..2e665cd 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -146,6 +146,13 @@ config OPPORTUNISTIC_SUSPEND
 	  determines the sleep state the system will be put into when there are
 	  no active suspend blockers.
 
+config USER_SUSPEND_BLOCKERS
+	bool "User space suspend blockers"
+	depends on OPPORTUNISTIC_SUSPEND
+	---help---
+	  User space suspend blockers API.  Creates a misc device allowing user
+	  space to create, use and destroy suspend blockers.
+
 config HIBERNATION_NVS
 	bool
 
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 95d8e6d..2015594 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PM_SLEEP)		+= console.o
 obj-$(CONFIG_FREEZER)		+= process.o
 obj-$(CONFIG_SUSPEND)		+= suspend.o
 obj-$(CONFIG_OPPORTUNISTIC_SUSPEND)	+= opportunistic_suspend.o
+obj-$(CONFIG_USER_SUSPEND_BLOCKERS)	+= user_suspend_blocker.o
 obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
 obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o
 obj-$(CONFIG_HIBERNATION_NVS)	+= hibernate_nvs.o
diff --git a/kernel/power/user_suspend_blocker.c b/kernel/power/user_suspend_blocker.c
new file mode 100644
index 0000000..d53f939
--- /dev/null
+++ b/kernel/power/user_suspend_blocker.c
@@ -0,0 +1,143 @@
+/*
+ * kernel/power/user_suspend_blocker.c
+ *
+ * Copyright (C) 2009-2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+#include <linux/suspend_ioctls.h>
+
+enum {
+	DEBUG_FAILURE	= BIT(0),
+};
+static int debug_mask = DEBUG_FAILURE;
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static DEFINE_MUTEX(ioctl_lock);
+
+#define USER_SUSPEND_BLOCKER_NAME_LEN 31
+
+struct user_suspend_blocker {
+	struct suspend_blocker	blocker;
+	char			name[USER_SUSPEND_BLOCKER_NAME_LEN + 1];
+	bool			registered;
+};
+
+static int user_suspend_blocker_open(struct inode *inode, struct file *filp)
+{
+	struct user_suspend_blocker *blocker;
+
+	blocker = kzalloc(sizeof(*blocker), GFP_KERNEL);
+	if (!blocker)
+		return -ENOMEM;
+
+	nonseekable_open(inode, filp);
+	strcpy(blocker->name, "(userspace)");
+	blocker->blocker.name = blocker->name;
+	filp->private_data = blocker;
+
+	return 0;
+}
+
+static int suspend_blocker_set_name(struct user_suspend_blocker *blocker,
+				    void __user *name, size_t name_len)
+{
+	if (blocker->registered)
+		return -EBUSY;
+
+	if (name_len > USER_SUSPEND_BLOCKER_NAME_LEN)
+		name_len = USER_SUSPEND_BLOCKER_NAME_LEN;
+
+	if (copy_from_user(blocker->name, name, name_len))
+		return -EFAULT;
+	blocker->name[name_len] = '\0';
+
+	return 0;
+}
+
+static long user_suspend_blocker_ioctl(struct file *filp, unsigned int cmd,
+					unsigned long _arg)
+{
+	void __user *arg = (void __user *)_arg;
+	struct user_suspend_blocker *blocker = filp->private_data;
+	long ret = 0;
+
+	mutex_lock(&ioctl_lock);
+	if ((cmd & ~IOCSIZE_MASK) == SUSPEND_BLOCKER_IOCTL_SET_NAME(0)) {
+		ret = suspend_blocker_set_name(blocker, arg, _IOC_SIZE(cmd));
+		goto done;
+	}
+	if (!blocker->registered) {
+		suspend_blocker_register(&blocker->blocker);
+		blocker->registered = true;
+	}
+	switch (cmd) {
+	case SUSPEND_BLOCKER_IOCTL_BLOCK:
+		suspend_block(&blocker->blocker);
+		break;
+
+	case SUSPEND_BLOCKER_IOCTL_UNBLOCK:
+		suspend_unblock(&blocker->blocker);
+		break;
+
+	default:
+		ret = -ENOTTY;
+	}
+done:
+	if (ret && (debug_mask & DEBUG_FAILURE))
+		pr_err("user_suspend_blocker_ioctl: cmd %x failed, %ld\n",
+			cmd, ret);
+	mutex_unlock(&ioctl_lock);
+	return ret;
+}
+
+static int user_suspend_blocker_release(struct inode *inode, struct file *filp)
+{
+	struct user_suspend_blocker *blocker = filp->private_data;
+
+	if (blocker->registered)
+		suspend_blocker_unregister(&blocker->blocker);
+	kfree(blocker);
+
+	return 0;
+}
+
+const struct file_operations user_suspend_blocker_fops = {
+	.open = user_suspend_blocker_open,
+	.release = user_suspend_blocker_release,
+	.unlocked_ioctl = user_suspend_blocker_ioctl,
+};
+
+struct miscdevice user_suspend_blocker_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "suspend_blocker",
+	.fops = &user_suspend_blocker_fops,
+};
+
+static int __init user_suspend_blocker_init(void)
+{
+	return misc_register(&user_suspend_blocker_device);
+}
+
+static void __exit user_suspend_blocker_exit(void)
+{
+	misc_deregister(&user_suspend_blocker_device);
+}
+
+module_init(user_suspend_blocker_init);
+module_exit(user_suspend_blocker_exit);
-- 
1.6.5.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active.
  2010-05-14  4:11   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
@ 2010-05-14  4:11     ` Arve Hjønnevåg
  2010-05-14  4:11       ` [PATCH 4/8] PM: suspend_block: Add debugfs file Arve Hjønnevåg
  0 siblings, 1 reply; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-14  4:11 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Rafael J. Wysocki, Arve Hjønnevåg, Len Brown,
	Pavel Machek, Andrew Morton, David Rientjes, Matt Helsley

If a suspend_blocker is active, suspend will fail anyway. Since
try_to_freeze_tasks can take up to 20 seconds to complete or fail, aborting
as soon as someone blocks suspend (e.g. from an interrupt handler) improves
the worst case wakeup latency.

On an older kernel where task freezing could fail for processes attached
to a debugger, this fixed a problem where the device sometimes hung for
20 seconds before the screen turned on.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
 kernel/power/process.c |   11 +++++++++--
 1 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/kernel/power/process.c b/kernel/power/process.c
index 71ae290..27d26d3 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -38,6 +38,7 @@ static int try_to_freeze_tasks(bool sig_only)
 	struct timeval start, end;
 	u64 elapsed_csecs64;
 	unsigned int elapsed_csecs;
+	bool wakeup = false;
 
 	do_gettimeofday(&start);
 
@@ -63,6 +64,10 @@ static int try_to_freeze_tasks(bool sig_only)
 				todo++;
 		} while_each_thread(g, p);
 		read_unlock(&tasklist_lock);
+		if (todo && suspend_is_blocked()) {
+			wakeup = true;
+			break;
+		}
 		if (!todo || time_after(jiffies, end_time))
 			break;
 
@@ -85,13 +90,15 @@ static int try_to_freeze_tasks(bool sig_only)
 		 * but it cleans up leftover PF_FREEZE requests.
 		 */
 		printk("\n");
-		printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds "
+		printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds "
 				"(%d tasks refusing to freeze):\n",
+				wakeup ? "aborted" : "failed",
 				elapsed_csecs / 100, elapsed_csecs % 100, todo);
 		read_lock(&tasklist_lock);
 		do_each_thread(g, p) {
 			task_lock(p);
-			if (freezing(p) && !freezer_should_skip(p))
+			if (freezing(p) && !freezer_should_skip(p)
+					&& elapsed_csecs > 100)
 				sched_show_task(p);
 			cancel_freezing(p);
 			task_unlock(p);
-- 
1.6.5.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 4/8] PM: suspend_block: Add debugfs file
  2010-05-14  4:11     ` [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active Arve Hjønnevåg
@ 2010-05-14  4:11       ` Arve Hjønnevåg
  2010-05-14  4:11         ` [PATCH 5/8] PM: suspend_block: Add suspend_blocker stats Arve Hjønnevåg
  0 siblings, 1 reply; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-14  4:11 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Rafael J. Wysocki, Arve Hjønnevåg, Len Brown,
	Pavel Machek, Tejun Heo

Report active and inactive suspend blockers in
/sys/kernel/debug/suspend_blockers.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 kernel/power/opportunistic_suspend.c |   43 +++++++++++++++++++++++++++++++++-
 1 files changed, 42 insertions(+), 1 deletions(-)

diff --git a/kernel/power/opportunistic_suspend.c b/kernel/power/opportunistic_suspend.c
index acc1651..c2dad76 100644
--- a/kernel/power/opportunistic_suspend.c
+++ b/kernel/power/opportunistic_suspend.c
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/rtc.h>
 #include <linux/suspend.h>
+#include <linux/debugfs.h>
 
 #include "power.h"
 
@@ -138,7 +139,8 @@ EXPORT_SYMBOL(suspend_blocker_register);
 /**
  * suspend_blocker_init - Initialize a suspend blocker's name and register it.
  * @blocker: Suspend blocker to initialize.
- * @name:    The name of the suspend blocker to show in debug messages.
+ * @name:    The name of the suspend blocker to show in debug messages and
+ *	     /sys/kernel/debug/suspend_blockers.
  *
  * The suspend blocker struct and name must not be freed before calling
  * suspend_blocker_unregister().
@@ -282,3 +284,42 @@ void __init opportunistic_suspend_init(void)
 	suspend_blocker_register(&main_suspend_blocker);
 	suspend_block(&main_suspend_blocker);
 }
+
+static struct dentry *suspend_blocker_stats_dentry;
+
+static int suspend_blocker_stats_show(struct seq_file *m, void *unused)
+{
+	unsigned long irqflags;
+	struct suspend_blocker *blocker;
+
+	seq_puts(m, "name\tactive\n");
+	spin_lock_irqsave(&list_lock, irqflags);
+	list_for_each_entry(blocker, &inactive_blockers, link)
+		seq_printf(m, "\"%s\"\t0\n", blocker->name);
+	list_for_each_entry(blocker, &active_blockers, link)
+		seq_printf(m, "\"%s\"\t1\n", blocker->name);
+	spin_unlock_irqrestore(&list_lock, irqflags);
+	return 0;
+}
+
+static int suspend_blocker_stats_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, suspend_blocker_stats_show, NULL);
+}
+
+static const struct file_operations suspend_blocker_stats_fops = {
+	.owner = THIS_MODULE,
+	.open = suspend_blocker_stats_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int __init suspend_blocker_debugfs_init(void)
+{
+	suspend_blocker_stats_dentry = debugfs_create_file("suspend_blockers",
+			S_IRUGO, NULL, NULL, &suspend_blocker_stats_fops);
+	return 0;
+}
+
+postcore_initcall(suspend_blocker_debugfs_init);
-- 
1.6.5.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 5/8] PM: suspend_block: Add suspend_blocker stats
  2010-05-14  4:11       ` [PATCH 4/8] PM: suspend_block: Add debugfs file Arve Hjønnevåg
@ 2010-05-14  4:11         ` Arve Hjønnevåg
  2010-05-14  4:11           ` [PATCH 6/8] PM: Add suspend blocking work Arve Hjønnevåg
  0 siblings, 1 reply; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-14  4:11 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Rafael J. Wysocki, Arve Hjønnevåg, Pavel Machek,
	Tejun Heo, Len Brown, Jesse Barnes, Magnus Damm, Wu Fengguang,
	Andrew Morton, Maxim Levitsky

Report suspend block stats in /sys/kernel/debug/suspend_blockers.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 include/linux/suspend_blocker.h      |   27 +++++-
 kernel/power/Kconfig                 |    8 ++
 kernel/power/opportunistic_suspend.c |  200 +++++++++++++++++++++++++++++++++-
 kernel/power/power.h                 |    5 +
 kernel/power/suspend.c               |    4 +-
 5 files changed, 239 insertions(+), 5 deletions(-)

diff --git a/include/linux/suspend_blocker.h b/include/linux/suspend_blocker.h
index 8788302..256af15 100755
--- a/include/linux/suspend_blocker.h
+++ b/include/linux/suspend_blocker.h
@@ -17,11 +17,35 @@
 #define _LINUX_SUSPEND_BLOCKER_H
 
 #include <linux/list.h>
+#include <linux/ktime.h>
+
+/**
+ * struct suspend_blocker_stats - statistics for a suspend blocker
+ *
+ * @count: Number of times this blocker has been deacivated.
+ * @wakeup_count: Number of times this blocker was the first to block suspend
+ *	after resume.
+ * @total_time: Total time this suspend blocker has prevented suspend.
+ * @prevent_suspend_time: Time this suspend blocker has prevented suspend while
+ *	user-space requested suspend.
+ * @max_time: Max time this suspend blocker has been continuously active.
+ * @last_time: Monotonic clock when the active state last changed.
+ */
+struct suspend_blocker_stats {
+#ifdef CONFIG_SUSPEND_BLOCKER_STATS
+	unsigned int count;
+	unsigned int wakeup_count;
+	ktime_t total_time;
+	ktime_t prevent_suspend_time;
+	ktime_t max_time;
+	ktime_t last_time;
+#endif
+};
 
 /**
  * struct suspend_blocker - the basic suspend_blocker structure
  * @link: List entry for active or inactive list.
- * @flags: Tracks initialized and active state.
+ * @flags: Tracks initialized and active state and statistics.
  * @name: Suspend blocker name used for debugging.
  *
  * When a suspend_blocker is active it prevents the system from entering
@@ -34,6 +58,7 @@ struct suspend_blocker {
 	struct list_head link;
 	int flags;
 	const char *name;
+	struct suspend_blocker_stats stat;
 #endif
 };
 
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 2e665cd..16a2570 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -146,6 +146,14 @@ config OPPORTUNISTIC_SUSPEND
 	  determines the sleep state the system will be put into when there are
 	  no active suspend blockers.
 
+config SUSPEND_BLOCKER_STATS
+	bool "Suspend blockers statistics"
+	depends on OPPORTUNISTIC_SUSPEND
+	default y
+	---help---
+	  Use /sys/kernel/debug/suspend_blockers to report suspend blockers
+	  statistics.
+
 config USER_SUSPEND_BLOCKERS
 	bool "User space suspend blockers"
 	depends on OPPORTUNISTIC_SUSPEND
diff --git a/kernel/power/opportunistic_suspend.c b/kernel/power/opportunistic_suspend.c
index c2dad76..3f0153d 100644
--- a/kernel/power/opportunistic_suspend.c
+++ b/kernel/power/opportunistic_suspend.c
@@ -35,6 +35,7 @@ module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
 
 #define SB_INITIALIZED            (1U << 8)
 #define SB_ACTIVE                 (1U << 9)
+#define SB_PREVENTING_SUSPEND     (1U << 10)
 
 DEFINE_SUSPEND_BLOCKER(main_suspend_blocker, main);
 
@@ -45,6 +46,118 @@ static LIST_HEAD(active_blockers);
 static int current_event_num;
 static suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
 static bool enable_suspend_blockers;
+static DEFINE_SUSPEND_BLOCKER(unknown_wakeup, unknown_wakeups);
+
+#ifdef CONFIG_SUSPEND_BLOCKER_STATS
+static struct suspend_blocker_stats dropped_suspend_blockers;
+static ktime_t last_sleep_time_update;
+static bool wait_for_wakeup;
+
+static void suspend_blocker_stat_init(struct suspend_blocker_stats *stat)
+{
+	stat->count = 0;
+	stat->wakeup_count = 0;
+	stat->total_time = ktime_set(0, 0);
+	stat->prevent_suspend_time = ktime_set(0, 0);
+	stat->max_time = ktime_set(0, 0);
+	stat->last_time = ktime_set(0, 0);
+}
+
+static void init_dropped_suspend_blockers(void)
+{
+	suspend_blocker_stat_init(&dropped_suspend_blockers);
+}
+
+static void suspend_blocker_stat_drop(struct suspend_blocker_stats *stat)
+{
+	if (!stat->count)
+		return;
+
+	dropped_suspend_blockers.count += stat->count;
+	dropped_suspend_blockers.total_time = ktime_add(
+		dropped_suspend_blockers.total_time, stat->total_time);
+	dropped_suspend_blockers.prevent_suspend_time = ktime_add(
+		dropped_suspend_blockers.prevent_suspend_time,
+		stat->prevent_suspend_time);
+	dropped_suspend_blockers.max_time = ktime_add(
+		dropped_suspend_blockers.max_time, stat->max_time);
+}
+
+static void suspend_unblock_stat(struct suspend_blocker *blocker)
+{
+	struct suspend_blocker_stats *stat = &blocker->stat;
+	ktime_t duration;
+	ktime_t now;
+
+	if (!(blocker->flags & SB_ACTIVE))
+		return;
+
+	now = ktime_get();
+	stat->count++;
+	duration = ktime_sub(now, stat->last_time);
+	stat->total_time = ktime_add(stat->total_time, duration);
+	if (ktime_to_ns(duration) > ktime_to_ns(stat->max_time))
+		stat->max_time = duration;
+
+	stat->last_time = ktime_get();
+	if (blocker->flags & SB_PREVENTING_SUSPEND) {
+		duration = ktime_sub(now, last_sleep_time_update);
+		stat->prevent_suspend_time = ktime_add(
+			stat->prevent_suspend_time, duration);
+		blocker->flags &= ~SB_PREVENTING_SUSPEND;
+	}
+}
+
+static void suspend_block_stat(struct suspend_blocker *blocker)
+{
+	if (wait_for_wakeup) {
+		if (debug_mask & DEBUG_WAKEUP)
+			pr_info("wakeup suspend blocker: %s\n", blocker->name);
+
+		wait_for_wakeup = false;
+		blocker->stat.wakeup_count++;
+	}
+	if (!(blocker->flags & SB_ACTIVE))
+		blocker->stat.last_time = ktime_get();
+}
+
+static void update_sleep_wait_stats(bool done)
+{
+	struct suspend_blocker *blocker;
+	ktime_t now, elapsed, add;
+
+	now = ktime_get();
+	elapsed = ktime_sub(now, last_sleep_time_update);
+	list_for_each_entry(blocker, &active_blockers, link) {
+		struct suspend_blocker_stats *stat = &blocker->stat;
+
+		if (blocker->flags & SB_PREVENTING_SUSPEND) {
+			add = elapsed;
+			stat->prevent_suspend_time = ktime_add(
+				stat->prevent_suspend_time, add);
+		}
+		if (done)
+			blocker->flags &= ~SB_PREVENTING_SUSPEND;
+		else
+			blocker->flags |= SB_PREVENTING_SUSPEND;
+	}
+	last_sleep_time_update = now;
+}
+
+void about_to_enter_suspend(void)
+{
+	wait_for_wakeup = true;
+}
+
+#else /* !CONFIG_SUSPEND_BLOCKER_STATS */
+
+static inline void init_dropped_suspend_blockers(void) {}
+static inline void suspend_blocker_stat_init(struct suspend_blocker_stats *s) {}
+static inline void suspend_blocker_stat_drop(struct suspend_blocker_stats *s) {}
+static inline void suspend_unblock_stat(struct suspend_blocker *blocker) {}
+static inline void suspend_block_stat(struct suspend_blocker *blocker) {}
+static inline void update_sleep_wait_stats(bool done) {}
+#endif /* !CONFIG_SUSPEND_BLOCKER_STATS */
 
 #define pr_info_time(fmt, args...) \
 	do { \
@@ -103,7 +216,8 @@ static void suspend_worker(struct work_struct *work)
 	if (current_event_num == entry_event_num) {
 		if (debug_mask & DEBUG_SUSPEND)
 			pr_info("PM: pm_suspend() returned with no event\n");
-		queue_work(pm_wq, work);
+		suspend_block(&unknown_wakeup);
+		suspend_unblock(&unknown_wakeup);
 	}
 
 abort:
@@ -127,6 +241,8 @@ void suspend_blocker_register(struct suspend_blocker *blocker)
 	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
 		pr_info("%s: Registering %s\n", __func__, blocker->name);
 
+	suspend_blocker_stat_init(&blocker->stat);
+
 	blocker->flags = SB_INITIALIZED;
 	INIT_LIST_HEAD(&blocker->link);
 
@@ -164,6 +280,10 @@ void suspend_blocker_unregister(struct suspend_blocker *blocker)
 		return;
 
 	spin_lock_irqsave(&list_lock, irqflags);
+
+	suspend_unblock_stat(blocker);
+	suspend_blocker_stat_drop(&blocker->stat);
+
 	blocker->flags &= ~SB_INITIALIZED;
 	list_del(&blocker->link);
 	if ((blocker->flags & SB_ACTIVE) && list_empty(&active_blockers))
@@ -193,11 +313,18 @@ void suspend_block(struct suspend_blocker *blocker)
 	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
 		pr_info("%s: %s\n", __func__, blocker->name);
 
+	suspend_block_stat(blocker);
+
 	blocker->flags |= SB_ACTIVE;
 	list_move(&blocker->link, &active_blockers);
 
 	current_event_num++;
 
+	if (blocker == &main_suspend_blocker)
+		update_sleep_wait_stats(true);
+	else if (!suspend_blocker_is_active(&main_suspend_blocker))
+		update_sleep_wait_stats(false);
+
 	spin_unlock_irqrestore(&list_lock, irqflags);
 }
 EXPORT_SYMBOL(suspend_block);
@@ -222,13 +349,19 @@ void suspend_unblock(struct suspend_blocker *blocker)
 	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
 		pr_info("%s: %s\n", __func__, blocker->name);
 
+	suspend_unblock_stat(blocker);
+
 	list_move(&blocker->link, &inactive_blockers);
 	if ((blocker->flags & SB_ACTIVE) && list_empty(&active_blockers))
 		queue_work(pm_wq, &suspend_work);
 	blocker->flags &= ~(SB_ACTIVE);
 
-	if ((debug_mask & DEBUG_SUSPEND) && blocker == &main_suspend_blocker)
-		print_active_suspend_blockers();
+	if (blocker == &main_suspend_blocker) {
+		if (debug_mask & DEBUG_SUSPEND)
+			print_active_suspend_blockers();
+
+		update_sleep_wait_stats(false);
+	}
 
 	spin_unlock_irqrestore(&list_lock, irqflags);
 }
@@ -283,10 +416,69 @@ void __init opportunistic_suspend_init(void)
 {
 	suspend_blocker_register(&main_suspend_blocker);
 	suspend_block(&main_suspend_blocker);
+	suspend_blocker_register(&unknown_wakeup);
+	init_dropped_suspend_blockers();
 }
 
 static struct dentry *suspend_blocker_stats_dentry;
 
+#ifdef CONFIG_SUSPEND_BLOCKER_STATS
+static int print_blocker_stats(struct seq_file *m, const char *name,
+				struct suspend_blocker_stats *stat, int flags)
+{
+	int lock_count = stat->count;
+	ktime_t active_time = ktime_set(0, 0);
+	ktime_t total_time = stat->total_time;
+	ktime_t max_time = stat->max_time;
+	ktime_t prevent_suspend_time = stat->prevent_suspend_time;
+
+	if (flags & SB_ACTIVE) {
+		ktime_t now, add_time;
+
+		now = ktime_get();
+		add_time = ktime_sub(now, stat->last_time);
+		lock_count++;
+		active_time = add_time;
+		total_time = ktime_add(total_time, add_time);
+		if (flags & SB_PREVENTING_SUSPEND)
+			prevent_suspend_time = ktime_add(prevent_suspend_time,
+					ktime_sub(now, last_sleep_time_update));
+		if (add_time.tv64 > max_time.tv64)
+			max_time = add_time;
+	}
+
+	return seq_printf(m, "\"%s\"\t%d\t%d\t%lld\t%lld\t%lld\t%lld\t%lld\n",
+			name, lock_count, stat->wakeup_count,
+			ktime_to_ns(active_time), ktime_to_ns(total_time),
+			ktime_to_ns(prevent_suspend_time),
+			ktime_to_ns(max_time),
+			ktime_to_ns(stat->last_time));
+}
+
+static int suspend_blocker_stats_show(struct seq_file *m, void *unused)
+{
+	unsigned long irqflags;
+	struct suspend_blocker *blocker;
+
+	seq_puts(m, "name\tcount\twake_count\tactive_since"
+		 "\ttotal_time\tsleep_time\tmax_time\tlast_change\n");
+
+	spin_lock_irqsave(&list_lock, irqflags);
+	list_for_each_entry(blocker, &active_blockers, link)
+		print_blocker_stats(m,
+				blocker->name, &blocker->stat, blocker->flags);
+
+	list_for_each_entry(blocker, &inactive_blockers, link)
+		print_blocker_stats(m,
+				blocker->name, &blocker->stat, blocker->flags);
+
+	print_blocker_stats(m, "deleted", &dropped_suspend_blockers, 0);
+	spin_unlock_irqrestore(&list_lock, irqflags);
+	return 0;
+}
+
+#else
+
 static int suspend_blocker_stats_show(struct seq_file *m, void *unused)
 {
 	unsigned long irqflags;
@@ -302,6 +494,8 @@ static int suspend_blocker_stats_show(struct seq_file *m, void *unused)
 	return 0;
 }
 
+#endif
+
 static int suspend_blocker_stats_open(struct inode *inode, struct file *file)
 {
 	return single_open(file, suspend_blocker_stats_show, NULL);
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 2e9cfd5..e13c975 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -245,3 +245,8 @@ extern void __init opportunistic_suspend_init(void);
 #else
 static inline void opportunistic_suspend_init(void) {}
 #endif
+#ifdef CONFIG_SUSPEND_BLOCKER_STATS
+void about_to_enter_suspend(void);
+#else
+static inline void about_to_enter_suspend(void) {}
+#endif
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 9eb3876..df694e7 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -158,8 +158,10 @@ static int suspend_enter(suspend_state_t state)
 
 	error = sysdev_suspend(PMSG_SUSPEND);
 	if (!error) {
-		if (!suspend_is_blocked() && !suspend_test(TEST_CORE))
+		if (!suspend_is_blocked() && !suspend_test(TEST_CORE)) {
+			about_to_enter_suspend();
 			error = suspend_ops->enter(state);
+		}
 		sysdev_resume();
 	}
 
-- 
1.6.5.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 6/8] PM: Add suspend blocking work.
  2010-05-14  4:11         ` [PATCH 5/8] PM: suspend_block: Add suspend_blocker stats Arve Hjønnevåg
@ 2010-05-14  4:11           ` Arve Hjønnevåg
  2010-05-14  4:11             ` [PATCH 7/8] Input: Block suspend while event queue is not empty Arve Hjønnevåg
  0 siblings, 1 reply; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-14  4:11 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Rafael J. Wysocki, Arve Hjønnevåg, Pavel Machek,
	Tejun Heo, Len Brown

Allow work to be queued that will block suspend while it is pending
or executing. To get the same functionality in the calling code often
requires a separate suspend_blocker for pending and executing work, or
additional state and locking. This implementation does add additional
state and locking, but this can be removed later if we add support for
suspend blocking work to the core workqueue code.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
Reviewed-by: Tejun Heo <tj@kernel.org>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
 include/linux/suspend_blocker.h      |   67 +++++++++++++++++++++
 kernel/power/opportunistic_suspend.c |  109 ++++++++++++++++++++++++++++++++++
 2 files changed, 176 insertions(+), 0 deletions(-)

diff --git a/include/linux/suspend_blocker.h b/include/linux/suspend_blocker.h
index 256af15..bb90b45 100755
--- a/include/linux/suspend_blocker.h
+++ b/include/linux/suspend_blocker.h
@@ -18,6 +18,7 @@
 
 #include <linux/list.h>
 #include <linux/ktime.h>
+#include <linux/workqueue.h>
 
 /**
  * struct suspend_blocker_stats - statistics for a suspend blocker
@@ -62,6 +63,38 @@ struct suspend_blocker {
 #endif
 };
 
+/**
+ * struct suspend_blocking_work - the basic suspend_blocking_work structure
+ * @work:		Standard work struct.
+ * @suspend_blocker:	Suspend blocker.
+ * @func:		Callback.
+ * @lock:		Spinlock protecting pending and running state.
+ * @active:		Number of cpu workqueues where work is pending or
+ *			callback is running.
+ *
+ * When suspend blocking work is pending or its callback is running it prevents
+ * the system from entering opportunistic suspend.
+ *
+ * The suspend_blocking_work structure must be initialized by
+ * suspend_blocking_work_init().
+ */
+
+struct suspend_blocking_work {
+	struct work_struct work;
+#ifdef CONFIG_OPPORTUNISTIC_SUSPEND
+	struct suspend_blocker suspend_blocker;
+	work_func_t func;
+	spinlock_t lock;
+	int active;
+#endif
+};
+
+static inline struct suspend_blocking_work *to_suspend_blocking_work(
+	struct work_struct *work)
+{
+	return container_of(work, struct suspend_blocking_work, work);
+}
+
 #ifdef CONFIG_OPPORTUNISTIC_SUSPEND
 #define __SUSPEND_BLOCKER_INITIALIZER(blocker_name) \
 	{ .name = #blocker_name, }
@@ -78,6 +111,14 @@ extern void suspend_unblock(struct suspend_blocker *blocker);
 extern bool suspend_blocker_is_active(struct suspend_blocker *blocker);
 extern bool suspend_is_blocked(void);
 
+void suspend_blocking_work_init(struct suspend_blocking_work *work,
+				work_func_t func, const char *name);
+void suspend_blocking_work_destroy(struct suspend_blocking_work *work);
+int queue_suspend_blocking_work(struct workqueue_struct *wq,
+				struct suspend_blocking_work *work);
+int schedule_suspend_blocking_work(struct suspend_blocking_work *work);
+int cancel_suspend_blocking_work_sync(struct suspend_blocking_work *work);
+
 #else
 
 #define DEFINE_SUSPEND_BLOCKER(blocker, name) \
@@ -94,6 +135,32 @@ static inline bool suspend_blocker_is_active(struct suspend_blocker *bl)
 	return false;
 }
 static inline bool suspend_is_blocked(void) { return false; }
+
+static inline void suspend_blocking_work_init(
+	struct suspend_blocking_work *work, work_func_t func, const char *name)
+{
+	INIT_WORK(&work->work, func);
+}
+static inline void suspend_blocking_work_destroy(
+	struct suspend_blocking_work *work)
+{
+	cancel_work_sync(&work->work);
+}
+static inline int queue_suspend_blocking_work(
+	struct workqueue_struct *wq, struct suspend_blocking_work *work)
+{
+	return queue_work(wq, &work->work);
+}
+static inline int schedule_suspend_blocking_work(
+	struct suspend_blocking_work *work)
+{
+	return schedule_work(&work->work);
+}
+static inline int cancel_suspend_blocking_work_sync(
+	struct suspend_blocking_work *work)
+{
+	return cancel_work_sync(&work->work);
+}
 #endif
 
 #endif
diff --git a/kernel/power/opportunistic_suspend.c b/kernel/power/opportunistic_suspend.c
index 3f0153d..63be9ad 100644
--- a/kernel/power/opportunistic_suspend.c
+++ b/kernel/power/opportunistic_suspend.c
@@ -517,3 +517,112 @@ static int __init suspend_blocker_debugfs_init(void)
 }
 
 postcore_initcall(suspend_blocker_debugfs_init);
+
+static void suspend_blocking_work_complete(struct suspend_blocking_work *work)
+{
+	unsigned long flags;
+
+	WARN_ON(!work->active);
+	spin_lock_irqsave(&work->lock, flags);
+	if (!--work->active)
+		suspend_unblock(&work->suspend_blocker);
+	spin_unlock_irqrestore(&work->lock, flags);
+}
+
+static void suspend_blocking_work_func(struct work_struct *work)
+{
+	struct suspend_blocking_work *sbwork = to_suspend_blocking_work(work);
+
+	sbwork->func(work);
+	suspend_blocking_work_complete(sbwork);
+}
+
+/**
+ * suspend_blocking_work_init - Initialize a suspend-blocking work item.
+ * @work: Work item to initialize.
+ * @func: Callback.
+ * @name: Name for suspend blocker.
+ *
+ */
+void suspend_blocking_work_init(struct suspend_blocking_work *work,
+				work_func_t func, const char *name)
+{
+	INIT_WORK(&work->work, suspend_blocking_work_func);
+	suspend_blocker_init(&work->suspend_blocker, name);
+	work->func = func;
+	spin_lock_init(&work->lock);
+	work->active = 0;
+}
+EXPORT_SYMBOL_GPL(suspend_blocking_work_init);
+
+/**
+ * cancel_suspend_blocking_work_sync - Cancel a suspend-blocking work item.
+ * @work: Work item to handle.
+ */
+int cancel_suspend_blocking_work_sync(struct suspend_blocking_work *work)
+{
+	int ret;
+
+	ret = cancel_work_sync(&work->work);
+	if (ret)
+		suspend_blocking_work_complete(work);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(cancel_suspend_blocking_work_sync);
+
+/**
+ * suspend_blocking_work_destroy - Destroy a suspend-blocking work item.
+ * @work: The work item in question.
+ *
+ * If the work was ever queued on more then one workqueue all but the last
+ * workqueue must be flushed before calling suspend_blocking_work_destroy.
+ */
+void suspend_blocking_work_destroy(struct suspend_blocking_work *work)
+{
+	cancel_suspend_blocking_work_sync(work);
+	WARN_ON(work->active);
+	suspend_blocker_unregister(&work->suspend_blocker);
+}
+EXPORT_SYMBOL_GPL(suspend_blocking_work_destroy);
+
+/**
+ * queue_suspend_blocking_work - Queue a suspend-blocking work item.
+ * @wq: Workqueue to queue the work on.
+ * @work: Work item to queue.
+ */
+int queue_suspend_blocking_work(struct workqueue_struct *wq,
+				struct suspend_blocking_work *work)
+{
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&work->lock, flags);
+	ret = queue_work(wq, &work->work);
+	if (ret) {
+		suspend_block(&work->suspend_blocker);
+		work->active++;
+	}
+	spin_unlock_irqrestore(&work->lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(queue_suspend_blocking_work);
+
+/**
+ * schedule_suspend_blocking_work - Schedule a suspend-blocking work item.
+ * @work: Work item to schedule.
+ */
+int schedule_suspend_blocking_work(struct suspend_blocking_work *work)
+{
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&work->lock, flags);
+	ret = schedule_work(&work->work);
+	if (ret) {
+		suspend_block(&work->suspend_blocker);
+		work->active++;
+	}
+	spin_unlock_irqrestore(&work->lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(schedule_suspend_blocking_work);
-- 
1.6.5.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 7/8] Input: Block suspend while event queue is not empty.
  2010-05-14  4:11           ` [PATCH 6/8] PM: Add suspend blocking work Arve Hjønnevåg
@ 2010-05-14  4:11             ` Arve Hjønnevåg
  2010-05-14  4:11               ` [PATCH 8/8] power_supply: Block suspend while power supply change notifications are pending Arve Hjønnevåg
  0 siblings, 1 reply; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-14  4:11 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Rafael J. Wysocki, Arve Hjønnevåg, Dmitry Torokhov,
	Márton Németh, Sven Neumann, Tero Saarni,
	Alexey Dobriyan, Matthew Garrett, Jiri Kosina, Henrik Rydberg,
	linux-input

Add an ioctl, EVIOCSSUSPENDBLOCK, to enable a suspend_blocker that will block
suspend while the event queue is not empty. This allows userspace code to
process input events while the device appears to be asleep.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 drivers/input/evdev.c |   22 ++++++++++++++++++++++
 include/linux/input.h |    3 +++
 2 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 2ee6c7a..bff2247 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -20,6 +20,7 @@
 #include <linux/input.h>
 #include <linux/major.h>
 #include <linux/device.h>
+#include <linux/suspend.h>
 #include "input-compat.h"
 
 struct evdev {
@@ -43,6 +44,8 @@ struct evdev_client {
 	struct fasync_struct *fasync;
 	struct evdev *evdev;
 	struct list_head node;
+	struct suspend_blocker suspend_blocker;
+	bool use_suspend_blocker;
 };
 
 static struct evdev *evdev_table[EVDEV_MINORS];
@@ -55,6 +58,8 @@ static void evdev_pass_event(struct evdev_client *client,
 	 * Interrupts are disabled, just acquire the lock
 	 */
 	spin_lock(&client->buffer_lock);
+	if (client->use_suspend_blocker)
+		suspend_block(&client->suspend_blocker);
 	client->buffer[client->head++] = *event;
 	client->head &= EVDEV_BUFFER_SIZE - 1;
 	spin_unlock(&client->buffer_lock);
@@ -234,6 +239,8 @@ static int evdev_release(struct inode *inode, struct file *file)
 	mutex_unlock(&evdev->mutex);
 
 	evdev_detach_client(evdev, client);
+	if (client->use_suspend_blocker)
+		suspend_blocker_unregister(&client->suspend_blocker);
 	kfree(client);
 
 	evdev_close_device(evdev);
@@ -335,6 +342,8 @@ static int evdev_fetch_next_event(struct evdev_client *client,
 	if (have_event) {
 		*event = client->buffer[client->tail++];
 		client->tail &= EVDEV_BUFFER_SIZE - 1;
+		if (client->use_suspend_blocker && client->head == client->tail)
+			suspend_unblock(&client->suspend_blocker);
 	}
 
 	spin_unlock_irq(&client->buffer_lock);
@@ -585,6 +594,19 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 		else
 			return evdev_ungrab(evdev, client);
 
+	case EVIOCGSUSPENDBLOCK:
+		return put_user(client->use_suspend_blocker, ip);
+
+	case EVIOCSSUSPENDBLOCK:
+		spin_lock_irq(&client->buffer_lock);
+		if (!client->use_suspend_blocker && p)
+			suspend_blocker_init(&client->suspend_blocker, "evdev");
+		else if (client->use_suspend_blocker && !p)
+			suspend_blocker_unregister(&client->suspend_blocker);
+		client->use_suspend_blocker = !!p;
+		spin_unlock_irq(&client->buffer_lock);
+		return 0;
+
 	default:
 
 		if (_IOC_TYPE(cmd) != 'E')
diff --git a/include/linux/input.h b/include/linux/input.h
index 7ed2251..b2d93b4 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -82,6 +82,9 @@ struct input_absinfo {
 
 #define EVIOCGRAB		_IOW('E', 0x90, int)			/* Grab/Release device */
 
+#define EVIOCGSUSPENDBLOCK	_IOR('E', 0x91, int)			/* get suspend block enable */
+#define EVIOCSSUSPENDBLOCK	_IOW('E', 0x91, int)			/* set suspend block enable */
+
 /*
  * Event types
  */
-- 
1.6.5.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 8/8] power_supply: Block suspend while power supply change notifications are pending
  2010-05-14  4:11             ` [PATCH 7/8] Input: Block suspend while event queue is not empty Arve Hjønnevåg
@ 2010-05-14  4:11               ` Arve Hjønnevåg
  0 siblings, 0 replies; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-14  4:11 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Rafael J. Wysocki, Arve Hjønnevåg, Anton Vorontsov,
	David Woodhouse, Daniel Mack, Andres Salomon, Len Brown,
	Mark Brown

When connecting usb or the charger the device would often go back to sleep
before the charge led and screen turned on.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 drivers/power/power_supply_core.c |    9 ++++++---
 include/linux/power_supply.h      |    3 ++-
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index cce75b4..577a131 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -39,7 +39,7 @@ static int __power_supply_changed_work(struct device *dev, void *data)
 static void power_supply_changed_work(struct work_struct *work)
 {
 	struct power_supply *psy = container_of(work, struct power_supply,
-						changed_work);
+						changed_work.work);
 
 	dev_dbg(psy->dev, "%s\n", __func__);
 
@@ -55,7 +55,7 @@ void power_supply_changed(struct power_supply *psy)
 {
 	dev_dbg(psy->dev, "%s\n", __func__);
 
-	schedule_work(&psy->changed_work);
+	schedule_suspend_blocking_work(&psy->changed_work);
 }
 EXPORT_SYMBOL_GPL(power_supply_changed);
 
@@ -155,7 +155,8 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
 		goto dev_create_failed;
 	}
 
-	INIT_WORK(&psy->changed_work, power_supply_changed_work);
+	suspend_blocking_work_init(&psy->changed_work,
+				   power_supply_changed_work, "power-supply");
 
 	rc = power_supply_create_attrs(psy);
 	if (rc)
@@ -172,6 +173,7 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
 create_triggers_failed:
 	power_supply_remove_attrs(psy);
 create_attrs_failed:
+	suspend_blocking_work_destroy(&psy->changed_work);
 	device_unregister(psy->dev);
 dev_create_failed:
 success:
@@ -184,6 +186,7 @@ void power_supply_unregister(struct power_supply *psy)
 	flush_scheduled_work();
 	power_supply_remove_triggers(psy);
 	power_supply_remove_attrs(psy);
+	suspend_blocking_work_destroy(&psy->changed_work);
 	device_unregister(psy->dev);
 }
 EXPORT_SYMBOL_GPL(power_supply_unregister);
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index ebd2b8f..f6412c8 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -14,6 +14,7 @@
 #define __LINUX_POWER_SUPPLY_H__
 
 #include <linux/device.h>
+#include <linux/suspend.h>
 #include <linux/workqueue.h>
 #include <linux/leds.h>
 
@@ -152,7 +153,7 @@ struct power_supply {
 
 	/* private */
 	struct device *dev;
-	struct work_struct changed_work;
+	struct suspend_blocking_work changed_work;
 
 #ifdef CONFIG_LEDS_TRIGGERS
 	struct led_trigger *charging_full_trig;
-- 
1.6.5.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-14  4:11 [PATCH 0/8] Suspend block api (version 7) Arve Hjønnevåg
  2010-05-14  4:11 ` [PATCH 1/8] PM: Add suspend block api Arve Hjønnevåg
@ 2010-05-14 21:08 ` Rafael J. Wysocki
  2010-05-17  4:50   ` Arve Hjønnevåg
  2010-05-16 19:42 ` Rafael J. Wysocki
  2 siblings, 1 reply; 53+ messages in thread
From: Rafael J. Wysocki @ 2010-05-14 21:08 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: linux-pm, linux-kernel, Greg KH, Mark Brown, Kevin Hilman,
	Alan Stern, Brian Swetland, Daniel Walker, Theodore Ts'o,
	Matthew Garrett

On Friday 14 May 2010, Arve Hjønnevåg wrote:
> This patch series adds a suspend-block api that provides the same
> functionality as the android wakelock api. This version has some
> changes from, or requested by, Rafael. The most notable changes are:
> - DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
>   for statically allocated suspend blockers. 
> - suspend_blocker_destroy is now called suspend_blocker_unregister
> - The user space mandatory _INIT ioctl has been replaced with an
>   optional _SET_NAME ioctl.
> 
> I kept the ack and reviewed by tags on two of the patches even though
> there were a few cosmetic changes.

Thanks for the patches, I think they are in a pretty good shape now.

That said, I'd like the changelogs to be a bit more descriptive, at least for
patch [1/8].  I think it should explain (in a few words) what the purpose of
the feature is and what problems it solves that generally a combination of
runtime PM and cpuidle is not suitable for in your opinion.  IOW, why you
think we need that feature.

The changelog of patch [2/8] appears to be outdated, that needs to be fixed.
Also, it would be nice to explain in the changelog what the interface is needed
for (in terms of the problems that it helps to handle).

Rafael

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-14  4:11 [PATCH 0/8] Suspend block api (version 7) Arve Hjønnevåg
  2010-05-14  4:11 ` [PATCH 1/8] PM: Add suspend block api Arve Hjønnevåg
  2010-05-14 21:08 ` [PATCH 0/8] Suspend block api (version 7) Rafael J. Wysocki
@ 2010-05-16 19:42 ` Rafael J. Wysocki
  2010-05-17  4:16   ` Arve Hjønnevåg
  2 siblings, 1 reply; 53+ messages in thread
From: Rafael J. Wysocki @ 2010-05-16 19:42 UTC (permalink / raw)
  To: Arve Hjønnevåg; +Cc: linux-pm, linux-kernel, Brian Swetland

On Friday 14 May 2010, Arve Hjønnevåg wrote:
> This patch series adds a suspend-block api that provides the same
> functionality as the android wakelock api. This version has some
> changes from, or requested by, Rafael. The most notable changes are:
> - DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
>   for statically allocated suspend blockers. 
> - suspend_blocker_destroy is now called suspend_blocker_unregister
> - The user space mandatory _INIT ioctl has been replaced with an
>   optional _SET_NAME ioctl.
> 
> I kept the ack and reviewed by tags on two of the patches even though
> there were a few cosmetic changes.

I have one more comment, sorry for that.

Namely, if /sys/power/policy is set to "opportunistic" and "mem" is written
into /sys/power/state and there are no suspend blockers present except for
the main blocker (and the blockers used only for statistics), the system won't
be able to go out of an infinit suspend-resume loop (or at least it seems
so from reading the code).

I think we should prevent that from happening somehow.

Thanks,
Rafael



^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-16 19:42 ` Rafael J. Wysocki
@ 2010-05-17  4:16   ` Arve Hjønnevåg
  2010-05-17 20:40     ` Rafael J. Wysocki
  0 siblings, 1 reply; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-17  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: linux-pm, linux-kernel, Brian Swetland

2010/5/16 Rafael J. Wysocki <rjw@sisk.pl>:
> On Friday 14 May 2010, Arve Hjønnevåg wrote:
>> This patch series adds a suspend-block api that provides the same
>> functionality as the android wakelock api. This version has some
>> changes from, or requested by, Rafael. The most notable changes are:
>> - DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
>>   for statically allocated suspend blockers.
>> - suspend_blocker_destroy is now called suspend_blocker_unregister
>> - The user space mandatory _INIT ioctl has been replaced with an
>>   optional _SET_NAME ioctl.
>>
>> I kept the ack and reviewed by tags on two of the patches even though
>> there were a few cosmetic changes.
>
> I have one more comment, sorry for that.
>
> Namely, if /sys/power/policy is set to "opportunistic" and "mem" is written
> into /sys/power/state and there are no suspend blockers present except for
> the main blocker (and the blockers used only for statistics), the system won't
> be able to go out of an infinit suspend-resume loop (or at least it seems
> so from reading the code).
>
> I think we should prevent that from happening somehow.
>

It should get out of that loop as soon as someone blocks suspend. If
someone is constantly aborting suspend without using a suspend blocker
it will be very inefficient, but it should still work.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-14 21:08 ` [PATCH 0/8] Suspend block api (version 7) Rafael J. Wysocki
@ 2010-05-17  4:50   ` Arve Hjønnevåg
  2010-05-17 19:01     ` Mike Snitzer
  2010-05-17 21:42     ` Rafael J. Wysocki
  0 siblings, 2 replies; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-17  4:50 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-pm, linux-kernel, Greg KH, Mark Brown, Kevin Hilman,
	Alan Stern, Brian Swetland, Daniel Walker, Theodore Ts'o,
	Matthew Garrett

2010/5/14 Rafael J. Wysocki <rjw@sisk.pl>:
> On Friday 14 May 2010, Arve Hjønnevåg wrote:
>> This patch series adds a suspend-block api that provides the same
>> functionality as the android wakelock api. This version has some
>> changes from, or requested by, Rafael. The most notable changes are:
>> - DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
>>   for statically allocated suspend blockers.
>> - suspend_blocker_destroy is now called suspend_blocker_unregister
>> - The user space mandatory _INIT ioctl has been replaced with an
>>   optional _SET_NAME ioctl.
>>
>> I kept the ack and reviewed by tags on two of the patches even though
>> there were a few cosmetic changes.
>
> Thanks for the patches, I think they are in a pretty good shape now.
>
> That said, I'd like the changelogs to be a bit more descriptive, at least for
> patch [1/8].  I think it should explain (in a few words) what the purpose of
> the feature is and what problems it solves that generally a combination of
> runtime PM and cpuidle is not suitable for in your opinion.  IOW, why you
> think we need that feature.
>

How about:

PM: Add opportunistic suspend support.

Adds a suspend block api that drivers can use to block opportunistic
suspend. This is needed to avoid losing wakeup events that occur
right after suspend is initiated.

Adds /sys/power/policy that selects the behaviour of /sys/power/state.
After setting the policy to opportunistic, writes to /sys/power/state
become non-blocking requests that specify which suspend state to enter
when no suspend blockers are active. A special state, "on", stops the
process by activating the "main" suspend blocker.

Opportunistic suspend is most useful on systems that cannot enter their
lowest power state from idle, but it is also useful on systems that enter
the same power state from idle and suspend. Periodic timers can cause
a significant power drain on these systems, and suspend will stop most
of this. Opportunistic suspend can also reduce the harm caused by apps
that never go idle.

> The changelog of patch [2/8] appears to be outdated, that needs to be fixed.
> Also, it would be nice to explain in the changelog what the interface is needed
> for (in terms of the problems that it helps to handle).
>

How about:

PM: suspend_block: Add driver to access suspend blockers from user-space

Add a misc device, "suspend_blocker", that allows user-space processes
to block auto suspend. Opening this device creates a suspend_blocker.
ioctls are provided to name this suspend_blocker, and to block and unblock
suspend. To delete the suspend_blocker, close the device.

For example, when select or poll indicates that input event are available, this
interface can be used to block suspend before reading those event. This allows
the input driver to release its suspend blocker as soon as the event queue is
empty.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-17  4:50   ` Arve Hjønnevåg
@ 2010-05-17 19:01     ` Mike Snitzer
  2010-05-17 21:42     ` Rafael J. Wysocki
  1 sibling, 0 replies; 53+ messages in thread
From: Mike Snitzer @ 2010-05-17 19:01 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: Rafael J. Wysocki, linux-pm, linux-kernel, Greg KH, Mark Brown,
	Kevin Hilman, Alan Stern, Brian Swetland, Daniel Walker,
	Theodore Ts'o, Matthew Garrett

2010/5/17 Arve Hjønnevåg <arve@android.com>:
> 2010/5/14 Rafael J. Wysocki <rjw@sisk.pl>:
>> On Friday 14 May 2010, Arve Hjønnevåg wrote:
>>> This patch series adds a suspend-block api that provides the same
>>> functionality as the android wakelock api. This version has some
>>> changes from, or requested by, Rafael. The most notable changes are:
>>> - DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
>>>   for statically allocated suspend blockers.
>>> - suspend_blocker_destroy is now called suspend_blocker_unregister
>>> - The user space mandatory _INIT ioctl has been replaced with an
>>>   optional _SET_NAME ioctl.
>>>
>>> I kept the ack and reviewed by tags on two of the patches even though
>>> there were a few cosmetic changes.
>>
>> Thanks for the patches, I think they are in a pretty good shape now.
>>
>> That said, I'd like the changelogs to be a bit more descriptive, at least for
>> patch [1/8].  I think it should explain (in a few words) what the purpose of
>> the feature is and what problems it solves that generally a combination of
>> runtime PM and cpuidle is not suitable for in your opinion.  IOW, why you
>> think we need that feature.
>>
>
> How about:
>
> PM: Add opportunistic suspend support.
>
> Adds a suspend block api

In the future I think it'd be ideal if you were to always use "suspend
blocker" (rather than "suspend block").

This work has nothing to do with the block layer yet by the subject I
thought it somehow did.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-17  4:16   ` Arve Hjønnevåg
@ 2010-05-17 20:40     ` Rafael J. Wysocki
  2010-05-17 20:51       ` Brian Swetland
  0 siblings, 1 reply; 53+ messages in thread
From: Rafael J. Wysocki @ 2010-05-17 20:40 UTC (permalink / raw)
  To: Arve Hjønnevåg; +Cc: linux-pm, linux-kernel, Brian Swetland

On Monday 17 May 2010, Arve Hjønnevåg wrote:
> 2010/5/16 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Friday 14 May 2010, Arve Hjønnevåg wrote:
> >> This patch series adds a suspend-block api that provides the same
> >> functionality as the android wakelock api. This version has some
> >> changes from, or requested by, Rafael. The most notable changes are:
> >> - DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
> >>   for statically allocated suspend blockers.
> >> - suspend_blocker_destroy is now called suspend_blocker_unregister
> >> - The user space mandatory _INIT ioctl has been replaced with an
> >>   optional _SET_NAME ioctl.
> >>
> >> I kept the ack and reviewed by tags on two of the patches even though
> >> there were a few cosmetic changes.
> >
> > I have one more comment, sorry for that.
> >
> > Namely, if /sys/power/policy is set to "opportunistic" and "mem" is written
> > into /sys/power/state and there are no suspend blockers present except for
> > the main blocker (and the blockers used only for statistics), the system won't
> > be able to go out of an infinit suspend-resume loop (or at least it seems
> > so from reading the code).
> >
> > I think we should prevent that from happening somehow.
> >
> 
> It should get out of that loop as soon as someone blocks suspend. If
> someone is constantly aborting suspend without using a suspend blocker
> it will be very inefficient, but it should still work.

Well, the scenario I have in mind is the following.  Someone wants to check
the feature and simply writes "opportunistic" to /sys/power/policy and "mem" to
/sys/power/state without any drivers or apps that use suspend blockers.

How in that case is the system supposed to break out of the suspend-resume loop
resulting from this?  I don't see right now, because the main blocker is
inactive, there are no other blockers that can be activated and it is next to
impossible to write to /sys/power/state again.

Rafael

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-17 20:40     ` Rafael J. Wysocki
@ 2010-05-17 20:51       ` Brian Swetland
  2010-05-17 21:44         ` Rafael J. Wysocki
  0 siblings, 1 reply; 53+ messages in thread
From: Brian Swetland @ 2010-05-17 20:51 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Arve Hjønnevåg, linux-pm, linux-kernel

On Mon, May 17, 2010 at 1:40 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> On Monday 17 May 2010, Arve Hjønnevåg wrote:
>>
>> It should get out of that loop as soon as someone blocks suspend. If
>> someone is constantly aborting suspend without using a suspend blocker
>> it will be very inefficient, but it should still work.
>
> Well, the scenario I have in mind is the following.  Someone wants to check
> the feature and simply writes "opportunistic" to /sys/power/policy and "mem" to
> /sys/power/state without any drivers or apps that use suspend blockers.
>
> How in that case is the system supposed to break out of the suspend-resume loop
> resulting from this?  I don't see right now, because the main blocker is
> inactive, there are no other blockers that can be activated and it is next to
> impossible to write to /sys/power/state again.

I guess we could set a flag when a suspend blocker is registered and
refuse to enter opportunistic mode if no blockers have ever been
registered.

It does seem like extra effort to go through to handle a "don't do
that" type scenario (entering into opportunistic suspend without
anything that will prevent it).

Brian

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-17  4:50   ` Arve Hjønnevåg
  2010-05-17 19:01     ` Mike Snitzer
@ 2010-05-17 21:42     ` Rafael J. Wysocki
  2010-05-17 22:16       ` Kevin Hilman
  2010-05-18  0:52       ` Arve Hjønnevåg
  1 sibling, 2 replies; 53+ messages in thread
From: Rafael J. Wysocki @ 2010-05-17 21:42 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: linux-pm, linux-kernel, Greg KH, Mark Brown, Kevin Hilman,
	Alan Stern, Brian Swetland, Daniel Walker, Theodore Ts'o,
	Matthew Garrett

On Monday 17 May 2010, Arve Hjønnevåg wrote:
> 2010/5/14 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Friday 14 May 2010, Arve Hjønnevåg wrote:
> >> This patch series adds a suspend-block api that provides the same
> >> functionality as the android wakelock api. This version has some
> >> changes from, or requested by, Rafael. The most notable changes are:
> >> - DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
> >>   for statically allocated suspend blockers.
> >> - suspend_blocker_destroy is now called suspend_blocker_unregister
> >> - The user space mandatory _INIT ioctl has been replaced with an
> >>   optional _SET_NAME ioctl.
> >>
> >> I kept the ack and reviewed by tags on two of the patches even though
> >> there were a few cosmetic changes.
> >
> > Thanks for the patches, I think they are in a pretty good shape now.
> >
> > That said, I'd like the changelogs to be a bit more descriptive, at least for
> > patch [1/8].  I think it should explain (in a few words) what the purpose of
> > the feature is and what problems it solves that generally a combination of
> > runtime PM and cpuidle is not suitable for in your opinion.  IOW, why you
> > think we need that feature.
> >
> 
> How about:
> 
> PM: Add opportunistic suspend support.

"PM: Opportunistic suspend support" would be sufficient IMO.

Now, I'd start with the motivation.  Like "Power management features present
in the current mainline kernel are insufficient to get maximum possible energy
savings on some platforms, such as Android, because ..." (here go explanations
why this is the case in your opinion).

Next, "To allow Android and similar platforms to save more energy than they
currently can save using the mainline kernel, introduce a mechanism by which
the system is automatically suspended (i.e. put into a system-wide sleep state)
whenever it's not doing useful work, called opportunistic suspend".

"For this purpose introduce the suspend blockers framework allowing the
kernel's power management subsystem to decide when it is desirable to suspend
the system (i.e. when useful work is not being done).  Add an API that ..."

> Adds a suspend block api that drivers can use to block opportunistic
> suspend. This is needed to avoid losing wakeup events that occur
> right after suspend is initiated.
>
> Adds /sys/power/policy that selects the behaviour of /sys/power/state.
> After setting the policy to opportunistic, writes to /sys/power/state
> become non-blocking requests that specify which suspend state to enter
> when no suspend blockers are active. A special state, "on", stops the
> process by activating the "main" suspend blocker.
> 
> Opportunistic suspend is most useful on systems that cannot enter their
> lowest power state from idle, but it is also useful on systems that enter
> the same power state from idle and suspend. Periodic timers can cause
> a significant power drain on these systems, and suspend will stop most
> of this. Opportunistic suspend can also reduce the harm caused by apps
> that never go idle.
> 
> > The changelog of patch [2/8] appears to be outdated, that needs to be fixed.
> > Also, it would be nice to explain in the changelog what the interface is needed
> > for (in terms of the problems that it helps to handle).
> >
> 
> How about:
> 
> PM: suspend_block: Add driver to access suspend blockers from user-space
> 
> Add a misc device, "suspend_blocker", that allows user-space processes
> to block auto suspend.

"automatic suspend" would be better IMO.

> Opening this device creates a suspend_blocker.

"suspend blocker that can be used by the opener to prevent automatic suspend
from occuring.  There are ioctls provided for blocking and unblocking suspend
and for giving the suspend blocker a meaningful name.  Closing the device
special file causes the suspend blocker to be destroyed."

> ioctls are provided to name this suspend_blocker, and to block and unblock
> suspend. To delete the suspend_blocker, close the device.
> 
> For example, when select or poll indicates that input event are available, this
> interface can be used to block suspend before reading those event. This allows
> the input driver to release its suspend blocker as soon as the event queue is
> empty.

I think you should explain in more detail how suspend blockers used by user
space make that possible.

Rafael

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-17 20:51       ` Brian Swetland
@ 2010-05-17 21:44         ` Rafael J. Wysocki
  2010-05-17 23:32           ` Arve Hjønnevåg
  0 siblings, 1 reply; 53+ messages in thread
From: Rafael J. Wysocki @ 2010-05-17 21:44 UTC (permalink / raw)
  To: Brian Swetland; +Cc: Arve Hjønnevåg, linux-pm, linux-kernel

On Monday 17 May 2010, Brian Swetland wrote:
> On Mon, May 17, 2010 at 1:40 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
> >>
> >> It should get out of that loop as soon as someone blocks suspend. If
> >> someone is constantly aborting suspend without using a suspend blocker
> >> it will be very inefficient, but it should still work.
> >
> > Well, the scenario I have in mind is the following.  Someone wants to check
> > the feature and simply writes "opportunistic" to /sys/power/policy and "mem" to
> > /sys/power/state without any drivers or apps that use suspend blockers.
> >
> > How in that case is the system supposed to break out of the suspend-resume loop
> > resulting from this?  I don't see right now, because the main blocker is
> > inactive, there are no other blockers that can be activated and it is next to
> > impossible to write to /sys/power/state again.
> 
> I guess we could set a flag when a suspend blocker is registered and
> refuse to enter opportunistic mode if no blockers have ever been
> registered.
> 
> It does seem like extra effort to go through to handle a "don't do
> that" type scenario (entering into opportunistic suspend without
> anything that will prevent it).

I agree, but I think it's necessary.  We shouldn't add interfaces that hurt
users if not used with care.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-17 21:42     ` Rafael J. Wysocki
@ 2010-05-17 22:16       ` Kevin Hilman
  2010-05-18  0:52       ` Arve Hjønnevåg
  1 sibling, 0 replies; 53+ messages in thread
From: Kevin Hilman @ 2010-05-17 22:16 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Arve Hjønnevåg, linux-pm, linux-kernel, Greg KH,
	Mark Brown, Alan Stern, Brian Swetland, Daniel Walker,
	Theodore Ts'o, Matthew Garrett

"Rafael J. Wysocki" <rjw@sisk.pl> writes:

> On Monday 17 May 2010, Arve Hjønnevåg wrote:

>> 
>> How about:
>> 
>> PM: Add opportunistic suspend support.
>
> "PM: Opportunistic suspend support" would be sufficient IMO.
>
> Now, I'd start with the motivation.  Like "Power management features present
> in the current mainline kernel are insufficient to get maximum possible energy
> savings on some platforms, such as Android, because ..." (here go explanations
> why this is the case in your opinion).

Yes, this will be helpful.

> Next, "To allow Android and similar platforms to save more energy than they
> currently can save using the mainline kernel, introduce a mechanism by which
> the system is automatically suspended (i.e. put into a system-wide sleep state)
> whenever it's not doing useful work, called opportunistic suspend".

Hopefully, a definition of "useful" will be given here, including by
what standards on-going work is determined not to be useful.

Kevin

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-17 21:44         ` Rafael J. Wysocki
@ 2010-05-17 23:32           ` Arve Hjønnevåg
  2010-05-18 19:38             ` Rafael J. Wysocki
  0 siblings, 1 reply; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-17 23:32 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Brian Swetland, linux-pm, linux-kernel

On Mon, May 17, 2010 at 2:44 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> On Monday 17 May 2010, Brian Swetland wrote:
>> On Mon, May 17, 2010 at 1:40 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
>> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
>> >>
>> >> It should get out of that loop as soon as someone blocks suspend. If
>> >> someone is constantly aborting suspend without using a suspend blocker
>> >> it will be very inefficient, but it should still work.
>> >
>> > Well, the scenario I have in mind is the following.  Someone wants to check
>> > the feature and simply writes "opportunistic" to /sys/power/policy and "mem" to
>> > /sys/power/state without any drivers or apps that use suspend blockers.
>> >
>> > How in that case is the system supposed to break out of the suspend-resume loop
>> > resulting from this?  I don't see right now, because the main blocker is
>> > inactive, there are no other blockers that can be activated and it is next to
>> > impossible to write to /sys/power/state again.
>>
>> I guess we could set a flag when a suspend blocker is registered and
>> refuse to enter opportunistic mode if no blockers have ever been
>> registered.
>>
>> It does seem like extra effort to go through to handle a "don't do
>> that" type scenario (entering into opportunistic suspend without
>> anything that will prevent it).
>
> I agree, but I think it's necessary.  We shouldn't add interfaces that hurt
> users if not used with care.
>

I'm not sure this can be "fixed". The user asked that the system to
suspend whenever possible, which is what it is doing. I don't think
disabling opportunistic suspend if no suspend blockers have been
registered will work. As soon as we register a suspend blocker we are
back in the same situation.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-17 21:42     ` Rafael J. Wysocki
  2010-05-17 22:16       ` Kevin Hilman
@ 2010-05-18  0:52       ` Arve Hjønnevåg
  2010-05-18 16:18         ` Kevin Hilman
  2010-05-18 19:13         ` Rafael J. Wysocki
  1 sibling, 2 replies; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-18  0:52 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-pm, linux-kernel, Greg KH, Mark Brown, Kevin Hilman,
	Alan Stern, Brian Swetland, Daniel Walker, Theodore Ts'o,
	Matthew Garrett

2010/5/17 Rafael J. Wysocki <rjw@sisk.pl>:
> On Monday 17 May 2010, Arve Hjønnevåg wrote:
>> 2010/5/14 Rafael J. Wysocki <rjw@sisk.pl>:
>> > On Friday 14 May 2010, Arve Hjønnevåg wrote:
>> >> This patch series adds a suspend-block api that provides the same
>> >> functionality as the android wakelock api. This version has some
>> >> changes from, or requested by, Rafael. The most notable changes are:
>> >> - DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
>> >>   for statically allocated suspend blockers.
>> >> - suspend_blocker_destroy is now called suspend_blocker_unregister
>> >> - The user space mandatory _INIT ioctl has been replaced with an
>> >>   optional _SET_NAME ioctl.
>> >>
>> >> I kept the ack and reviewed by tags on two of the patches even though
>> >> there were a few cosmetic changes.
>> >
>> > Thanks for the patches, I think they are in a pretty good shape now.
>> >
>> > That said, I'd like the changelogs to be a bit more descriptive, at least for
>> > patch [1/8].  I think it should explain (in a few words) what the purpose of
>> > the feature is and what problems it solves that generally a combination of
>> > runtime PM and cpuidle is not suitable for in your opinion.  IOW, why you
>> > think we need that feature.
>> >
>>
>> How about:
>>
>> PM: Add opportunistic suspend support.
>
> "PM: Opportunistic suspend support" would be sufficient IMO.
>
> Now, I'd start with the motivation.  Like "Power management features present
> in the current mainline kernel are insufficient to get maximum possible energy
> savings on some platforms, such as Android, because ..." (here go explanations
> why this is the case in your opinion).
>
> Next, "To allow Android and similar platforms to save more energy than they
> currently can save using the mainline kernel, introduce a mechanism by which
> the system is automatically suspended (i.e. put into a system-wide sleep state)
> whenever it's not doing useful work, called opportunistic suspend".
>
> "For this purpose introduce the suspend blockers framework allowing the
> kernel's power management subsystem to decide when it is desirable to suspend
> the system (i.e. when useful work is not being done).  Add an API that ..."
>

PM: Opportunistic suspend support.

Power management features present in the current mainline kernel are
insufficient to get maximum possible energy savings on some platforms,
such as Android, because low power states can only safely be entered
from idle. Suspend, in its current form, cannot be used, since wakeup
events that occur right after initiating suspend will not be processed
until another possibly unrelated event wake up the system again.

On some systems idle combined with runtime PM can enter the same power
state as suspend, but periodic wakeups increase the average power
consumption. Suspending the system also reduces the harm caused by
apps that never go idle. On other systems suspend can enter a much
lower power state than idle.

To allow Android and similar platforms to save more energy than they
currently can save using the mainline kernel, we introduce a mechanism
by which the system is automatically suspended (i.e. put into a
system-wide sleep state) whenever it's not doing useful work, called
opportunistic suspend.

For this purpose introduce the suspend blockers framework allowing the
kernel's power management subsystem to decide when it is desirable to
suspend the system (i.e. when useful work is not being done). Add an
API that that drivers can use to block opportunistic suspend. This is
needed to avoid losing wakeup events that occur right after suspend is
initiated.

Adds /sys/power/policy that selects the behavior of /sys/power/state.
After setting the policy to opportunistic, writes to /sys/power/state
become non-blocking requests that specify which suspend state to enter
when no suspend blockers are active. A special state, "on", stops the
process by activating the "main" suspend blocker.


>> Adds a suspend block api that drivers can use to block opportunistic
>> suspend. This is needed to avoid losing wakeup events that occur
>> right after suspend is initiated.
>>
>> Adds /sys/power/policy that selects the behaviour of /sys/power/state.
>> After setting the policy to opportunistic, writes to /sys/power/state
>> become non-blocking requests that specify which suspend state to enter
>> when no suspend blockers are active. A special state, "on", stops the
>> process by activating the "main" suspend blocker.
>>
>> Opportunistic suspend is most useful on systems that cannot enter their
>> lowest power state from idle, but it is also useful on systems that enter
>> the same power state from idle and suspend. Periodic timers can cause
>> a significant power drain on these systems, and suspend will stop most
>> of this. Opportunistic suspend can also reduce the harm caused by apps
>> that never go idle.
>>
>> > The changelog of patch [2/8] appears to be outdated, that needs to be fixed.
>> > Also, it would be nice to explain in the changelog what the interface is needed
>> > for (in terms of the problems that it helps to handle).
>> >
>>
>> How about:
>>
>> PM: suspend_block: Add driver to access suspend blockers from user-space
>>
>> Add a misc device, "suspend_blocker", that allows user-space processes
>> to block auto suspend.
>
> "automatic suspend" would be better IMO.
>
>> Opening this device creates a suspend_blocker.
>
> "suspend blocker that can be used by the opener to prevent automatic suspend
> from occuring.  There are ioctls provided for blocking and unblocking suspend
> and for giving the suspend blocker a meaningful name.  Closing the device
> special file causes the suspend blocker to be destroyed."
>
>> ioctls are provided to name this suspend_blocker, and to block and unblock
>> suspend. To delete the suspend_blocker, close the device.
>>
>> For example, when select or poll indicates that input event are available, this
>> interface can be used to block suspend before reading those event. This allows
>> the input driver to release its suspend blocker as soon as the event queue is
>> empty.
>
> I think you should explain in more detail how suspend blockers used by user
> space make that possible.
>


PM: suspend_block: Add driver to access suspend blockers from user-space

Add a misc device, "suspend_blocker", that allows user-space processes
to block automatic suspend.

Opening this device creates a suspend blocker that can be used by the
opener to prevent automatic suspend from occurring.  There are ioctls
provided for blocking and unblocking suspend and for giving the
suspend blocker a meaningful name.  Closing the device special file
causes the suspend blocker to be destroyed.

For example, when select or poll indicates that input event are
available, this interface can be used by user space to block suspend
before it reads those events. This allows the input driver to release
its suspend blocker as soon as the event queue is empty. If user space
could not use a suspend blocker here the input driver would need to
delay the release of its suspend blocker until it knows (or assumes)
that user space has finished processing the events.

By careful use of suspend blockers in drivers and user space system
code, one can arrange for the system to stay awake for extremely short
periods of time in reaction to events, rapidly returning to a fully
suspended state.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2010-05-14  4:11 ` [PATCH 1/8] PM: Add suspend block api Arve Hjønnevåg
  2010-05-14  4:11   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
@ 2010-05-18 13:11   ` Pavel Machek
  2010-05-20  9:11     ` Florian Mickler
  1 sibling, 1 reply; 53+ messages in thread
From: Pavel Machek @ 2010-05-18 13:11 UTC (permalink / raw)
  To: Arve Hj??nnev??g
  Cc: linux-pm, linux-kernel, Rafael J. Wysocki, Len Brown,
	Randy Dunlap, Andrew Morton, Andi Kleen, Cornelia Huck,
	Tejun Heo, Jesse Barnes, Magnus Damm, Nigel Cunningham,
	Alan Stern, Ming Lei, Wu Fengguang, Maxim Levitsky, linux-doc

On Thu 2010-05-13 21:11:06, Arve Hj??nnev??g wrote:
> Adds /sys/power/policy that selects the behaviour of /sys/power/state.
> After setting the policy to opportunistic, writes to /sys/power/state
> become non-blocking requests that specify which suspend state to
> enter

Yeah, one file selects behavior of another file, and to read available
states for opportunistic, you have to write to file first.

I still don't like the interface.

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18  0:52       ` Arve Hjønnevåg
@ 2010-05-18 16:18         ` Kevin Hilman
  2010-05-18 18:52           ` Rafael J. Wysocki
  2010-05-19  0:00           ` Arve Hjønnevåg
  2010-05-18 19:13         ` Rafael J. Wysocki
  1 sibling, 2 replies; 53+ messages in thread
From: Kevin Hilman @ 2010-05-18 16:18 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: Rafael J. Wysocki, linux-pm, linux-kernel, Greg KH, Mark Brown,
	Alan Stern, Brian Swetland, Daniel Walker, Theodore Ts'o,
	Matthew Garrett

Arve Hjønnevåg <arve@android.com> writes:

>
> PM: Opportunistic suspend support.
>
> Power management features present in the current mainline kernel are
> insufficient to get maximum possible energy savings on some platforms,
> such as Android, because low power states can only safely be entered
> from idle.  Suspend, in its current form, cannot be used, since wakeup
> events that occur right after initiating suspend will not be processed
> until another possibly unrelated event wake up the system again.

I think the problems with wakeups in the current suspend path need to
be described in more detail.  In particular, why check_wakeup_irqs()
is not enough etc.

> On some systems idle combined with runtime PM can enter the same power
> state as suspend, but periodic wakeups increase the average power
> consumption. Suspending the system also reduces the harm caused by
> apps that never go idle. On other systems suspend can enter a much
> lower power state than idle.
>
> To allow Android and similar platforms to save more energy than they
> currently can save using the mainline kernel, we introduce a mechanism
> by which the system is automatically suspended (i.e. put into a
> system-wide sleep state) whenever it's not doing useful work, called
> opportunistic suspend.

A definition of "useful work" here would provide clarity and would
also help clarify by what criteria other on-going work is determined
to be not useful.

Kevin

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18 16:18         ` Kevin Hilman
@ 2010-05-18 18:52           ` Rafael J. Wysocki
  2010-05-18 22:04             ` Kevin Hilman
  2010-05-19  0:00           ` Arve Hjønnevåg
  1 sibling, 1 reply; 53+ messages in thread
From: Rafael J. Wysocki @ 2010-05-18 18:52 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Arve Hjønnevåg, linux-pm, linux-kernel, Greg KH,
	Mark Brown, Alan Stern, Brian Swetland, Daniel Walker,
	Theodore Ts'o, Matthew Garrett

On Tuesday 18 May 2010, Kevin Hilman wrote:
> Arve Hjønnevåg <arve@android.com> writes:
> 
> >
> > PM: Opportunistic suspend support.
> >
> > Power management features present in the current mainline kernel are
> > insufficient to get maximum possible energy savings on some platforms,
> > such as Android, because low power states can only safely be entered
> > from idle.  Suspend, in its current form, cannot be used, since wakeup
> > events that occur right after initiating suspend will not be processed
> > until another possibly unrelated event wake up the system again.
> 
> I think the problems with wakeups in the current suspend path need to
> be described in more detail.  In particular, why check_wakeup_irqs()
> is not enough etc.

That one is really easy.: because some (the majority of?) architectures
don't even implement it.
 
> > On some systems idle combined with runtime PM can enter the same power
> > state as suspend, but periodic wakeups increase the average power
> > consumption. Suspending the system also reduces the harm caused by
> > apps that never go idle. On other systems suspend can enter a much
> > lower power state than idle.
> >
> > To allow Android and similar platforms to save more energy than they
> > currently can save using the mainline kernel, we introduce a mechanism
> > by which the system is automatically suspended (i.e. put into a
> > system-wide sleep state) whenever it's not doing useful work, called
> > opportunistic suspend.
> 
> A definition of "useful work" here would provide clarity and would
> also help clarify by what criteria other on-going work is determined
> to be not useful.

Probably "useful" is not the right word here.  I guess it's more like
"work that can be deferred without visible impact on functionality".

Rafael

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18  0:52       ` Arve Hjønnevåg
  2010-05-18 16:18         ` Kevin Hilman
@ 2010-05-18 19:13         ` Rafael J. Wysocki
  2010-05-18 20:47           ` Arve Hjønnevåg
  1 sibling, 1 reply; 53+ messages in thread
From: Rafael J. Wysocki @ 2010-05-18 19:13 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: linux-pm, linux-kernel, Greg KH, Mark Brown, Kevin Hilman,
	Alan Stern, Brian Swetland, Daniel Walker, Theodore Ts'o,
	Matthew Garrett

On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
> 2010/5/17 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
> >> 2010/5/14 Rafael J. Wysocki <rjw@sisk.pl>:
> >> > On Friday 14 May 2010, Arve Hjønnevåg wrote:
> >> >> This patch series adds a suspend-block api that provides the same
> >> >> functionality as the android wakelock api. This version has some
> >> >> changes from, or requested by, Rafael. The most notable changes are:
> >> >> - DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
> >> >>   for statically allocated suspend blockers.
> >> >> - suspend_blocker_destroy is now called suspend_blocker_unregister
> >> >> - The user space mandatory _INIT ioctl has been replaced with an
> >> >>   optional _SET_NAME ioctl.
> >> >>
> >> >> I kept the ack and reviewed by tags on two of the patches even though
> >> >> there were a few cosmetic changes.
> >> >
> >> > Thanks for the patches, I think they are in a pretty good shape now.
> >> >
> >> > That said, I'd like the changelogs to be a bit more descriptive, at least for
> >> > patch [1/8].  I think it should explain (in a few words) what the purpose of
> >> > the feature is and what problems it solves that generally a combination of
> >> > runtime PM and cpuidle is not suitable for in your opinion.  IOW, why you
> >> > think we need that feature.
> >> >
> >>
> >> How about:
> >>
> >> PM: Add opportunistic suspend support.
> >
> > "PM: Opportunistic suspend support" would be sufficient IMO.
> >
> > Now, I'd start with the motivation.  Like "Power management features present
> > in the current mainline kernel are insufficient to get maximum possible energy
> > savings on some platforms, such as Android, because ..." (here go explanations
> > why this is the case in your opinion).
> >
> > Next, "To allow Android and similar platforms to save more energy than they
> > currently can save using the mainline kernel, introduce a mechanism by which
> > the system is automatically suspended (i.e. put into a system-wide sleep state)
> > whenever it's not doing useful work, called opportunistic suspend".
> >
> > "For this purpose introduce the suspend blockers framework allowing the
> > kernel's power management subsystem to decide when it is desirable to suspend
> > the system (i.e. when useful work is not being done).  Add an API that ..."
> >
> 
> PM: Opportunistic suspend support.
> 
> Power management features present in the current mainline kernel are
> insufficient to get maximum possible energy savings on some platforms,
> such as Android, because low power states can only safely be entered
> from idle.

Do you mean CPU low-power states or system low-power states here?

I'd add more details here, because it may not be completely clear to the
(interested) reader why entering these states only from idle affects the
possibility to achieve maximum energy savings.  I _guess_ you mean that
using idle is not sufficient, because there are so many wakeups on the
systems in question that more savings are still possible.  Is that correct?

> Suspend, in its current form, cannot be used, since wakeup
> events that occur right after initiating suspend will not be processed
> until another possibly unrelated event wake up the system again.

I think the word "cannot" is too strong here.  I'd say "not suitable" instead
and I'd say what kind of wakeup events I meant more precisely (there are
events that wake up a CPU from idle and events that wake up the system from
suspend).

> On some systems idle combined with runtime PM can enter the same power
> state as suspend, but periodic wakeups increase the average power
> consumption. Suspending the system also reduces the harm caused by
> apps that never go idle. On other systems suspend can enter a much
> lower power state than idle.
> 
> To allow Android and similar platforms to save more energy than they
> currently can save using the mainline kernel, we introduce a mechanism

Just "introduce" without "we" works too.

> by which the system is automatically suspended (i.e. put into a
> system-wide sleep state) whenever it's not doing useful work, called
> opportunistic suspend.

I think we can address the Kevin's comment about "useful" and say "whenever
it's only doing work that can be done later without noticeable effect on
functionality".

> For this purpose introduce the suspend blockers framework allowing the
> kernel's power management subsystem to decide when it is desirable to
> suspend the system (i.e. when useful work is not being done). Add an

Perhaps remove the part in parens entirely.

> API that that drivers can use to block opportunistic suspend. This is
> needed to avoid losing wakeup events that occur right after suspend is
> initiated.
> 
> Adds /sys/power/policy that selects the behavior of /sys/power/state.
> After setting the policy to opportunistic, writes to /sys/power/state
> become non-blocking requests that specify which suspend state to enter
> when no suspend blockers are active. A special state, "on", stops the
> process by activating the "main" suspend blocker.

...
 
> PM: suspend_block: Add driver to access suspend blockers from user-space
> 
> Add a misc device, "suspend_blocker", that allows user-space processes
> to block automatic suspend.
> 
> Opening this device creates a suspend blocker that can be used by the
> opener to prevent automatic suspend from occurring.  There are ioctls
> provided for blocking and unblocking suspend and for giving the
> suspend blocker a meaningful name.  Closing the device special file
> causes the suspend blocker to be destroyed.
> 
> For example, when select or poll indicates that input event are
> available, this interface can be used by user space to block suspend
> before it reads those events. This allows the input driver to release
> its suspend blocker as soon as the event queue is empty. If user space
> could not use a suspend blocker here the input driver would need to
> delay the release of its suspend blocker until it knows (or assumes)
> that user space has finished processing the events.
> 
> By careful use of suspend blockers in drivers and user space system
> code, one can arrange for the system to stay awake for extremely short
> periods of time in reaction to events, rapidly returning to a fully
> suspended state.

That's fine by me.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-17 23:32           ` Arve Hjønnevåg
@ 2010-05-18 19:38             ` Rafael J. Wysocki
  2010-05-18 20:35               ` Arve Hjønnevåg
  0 siblings, 1 reply; 53+ messages in thread
From: Rafael J. Wysocki @ 2010-05-18 19:38 UTC (permalink / raw)
  To: Arve Hjønnevåg; +Cc: Brian Swetland, linux-pm, linux-kernel

On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
> On Mon, May 17, 2010 at 2:44 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> > On Monday 17 May 2010, Brian Swetland wrote:
> >> On Mon, May 17, 2010 at 1:40 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> >> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
> >> >>
> >> >> It should get out of that loop as soon as someone blocks suspend. If
> >> >> someone is constantly aborting suspend without using a suspend blocker
> >> >> it will be very inefficient, but it should still work.
> >> >
> >> > Well, the scenario I have in mind is the following.  Someone wants to check
> >> > the feature and simply writes "opportunistic" to /sys/power/policy and "mem" to
> >> > /sys/power/state without any drivers or apps that use suspend blockers.
> >> >
> >> > How in that case is the system supposed to break out of the suspend-resume loop
> >> > resulting from this?  I don't see right now, because the main blocker is
> >> > inactive, there are no other blockers that can be activated and it is next to
> >> > impossible to write to /sys/power/state again.
> >>
> >> I guess we could set a flag when a suspend blocker is registered and
> >> refuse to enter opportunistic mode if no blockers have ever been
> >> registered.
> >>
> >> It does seem like extra effort to go through to handle a "don't do
> >> that" type scenario (entering into opportunistic suspend without
> >> anything that will prevent it).
> >
> > I agree, but I think it's necessary.  We shouldn't add interfaces that hurt
> > users if not used with care.
> >
> 
> I'm not sure this can be "fixed".

Yes, it can, but perhaps a workaround would be sufficient (see below).

> The user asked that the system to suspend whenever possible, which is what it
> is doing. I don't think disabling opportunistic suspend if no suspend
> blockers have been registered will work. As soon as we register a suspend
> blocker we are back in the same situation.

Not really, because the new suspend blocker is not added by the _framework_ _itself_.

Now, to make it more "user-friendly", we can simply use
queue_delayed_work() with a reasonable delay instead of queue_work() to queue
the suspend work (the delay may be configurable via sysfs).

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18 19:38             ` Rafael J. Wysocki
@ 2010-05-18 20:35               ` Arve Hjønnevåg
  2010-05-18 21:14                 ` Rafael J. Wysocki
  0 siblings, 1 reply; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-18 20:35 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Brian Swetland, linux-pm, linux-kernel

2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
>> On Mon, May 17, 2010 at 2:44 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
>> > On Monday 17 May 2010, Brian Swetland wrote:
>> >> On Mon, May 17, 2010 at 1:40 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
>> >> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
>> >> >>
>> >> >> It should get out of that loop as soon as someone blocks suspend. If
>> >> >> someone is constantly aborting suspend without using a suspend blocker
>> >> >> it will be very inefficient, but it should still work.
>> >> >
>> >> > Well, the scenario I have in mind is the following.  Someone wants to check
>> >> > the feature and simply writes "opportunistic" to /sys/power/policy and "mem" to
>> >> > /sys/power/state without any drivers or apps that use suspend blockers.
>> >> >
>> >> > How in that case is the system supposed to break out of the suspend-resume loop
>> >> > resulting from this?  I don't see right now, because the main blocker is
>> >> > inactive, there are no other blockers that can be activated and it is next to
>> >> > impossible to write to /sys/power/state again.
>> >>
>> >> I guess we could set a flag when a suspend blocker is registered and
>> >> refuse to enter opportunistic mode if no blockers have ever been
>> >> registered.
>> >>
>> >> It does seem like extra effort to go through to handle a "don't do
>> >> that" type scenario (entering into opportunistic suspend without
>> >> anything that will prevent it).
>> >
>> > I agree, but I think it's necessary.  We shouldn't add interfaces that hurt
>> > users if not used with care.
>> >
>>
>> I'm not sure this can be "fixed".
>
> Yes, it can, but perhaps a workaround would be sufficient (see below).
>
>> The user asked that the system to suspend whenever possible, which is what it
>> is doing. I don't think disabling opportunistic suspend if no suspend
>> blockers have been registered will work. As soon as we register a suspend
>> blocker we are back in the same situation.
>
> Not really, because the new suspend blocker is not added by the _framework_ _itself_.
>

I'm not sure what you mean by this. If we add a workaround that is
disabled when the first suspend blocker is registered, then we cannot
add any suspend blockers without disabling the workaround (for
instance the power supply framework patch later in this patch set).

> Now, to make it more "user-friendly", we can simply use
> queue_delayed_work() with a reasonable delay instead of queue_work() to queue
> the suspend work (the delay may be configurable via sysfs).
>

I can add a delay (and the timeout support code does add a delay as an
optimization) to the unknown wakeup case, but this does not fix the
problem of a user turning on opportunistic suspend with a user space
framework that does not use suspend blockers. If the kernel uses
suspend blockers to make sure the wakeup event makes it to user space,
but user space does not block suspend, then the system will suspend
before the event is processed.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18 19:13         ` Rafael J. Wysocki
@ 2010-05-18 20:47           ` Arve Hjønnevåg
  2010-05-18 21:48             ` Rafael J. Wysocki
  0 siblings, 1 reply; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-18 20:47 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-pm, linux-kernel, Greg KH, Mark Brown, Kevin Hilman,
	Alan Stern, Brian Swetland, Daniel Walker, Theodore Ts'o,
	Matthew Garrett

2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
>> 2010/5/17 Rafael J. Wysocki <rjw@sisk.pl>:
>> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
>> >> 2010/5/14 Rafael J. Wysocki <rjw@sisk.pl>:
>> >> > On Friday 14 May 2010, Arve Hjønnevåg wrote:
>> >> >> This patch series adds a suspend-block api that provides the same
>> >> >> functionality as the android wakelock api. This version has some
>> >> >> changes from, or requested by, Rafael. The most notable changes are:
>> >> >> - DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
>> >> >>   for statically allocated suspend blockers.
>> >> >> - suspend_blocker_destroy is now called suspend_blocker_unregister
>> >> >> - The user space mandatory _INIT ioctl has been replaced with an
>> >> >>   optional _SET_NAME ioctl.
>> >> >>
>> >> >> I kept the ack and reviewed by tags on two of the patches even though
>> >> >> there were a few cosmetic changes.
>> >> >
>> >> > Thanks for the patches, I think they are in a pretty good shape now.
>> >> >
>> >> > That said, I'd like the changelogs to be a bit more descriptive, at least for
>> >> > patch [1/8].  I think it should explain (in a few words) what the purpose of
>> >> > the feature is and what problems it solves that generally a combination of
>> >> > runtime PM and cpuidle is not suitable for in your opinion.  IOW, why you
>> >> > think we need that feature.
>> >> >
>> >>
>> >> How about:
>> >>
>> >> PM: Add opportunistic suspend support.
>> >
>> > "PM: Opportunistic suspend support" would be sufficient IMO.
>> >
>> > Now, I'd start with the motivation.  Like "Power management features present
>> > in the current mainline kernel are insufficient to get maximum possible energy
>> > savings on some platforms, such as Android, because ..." (here go explanations
>> > why this is the case in your opinion).
>> >
>> > Next, "To allow Android and similar platforms to save more energy than they
>> > currently can save using the mainline kernel, introduce a mechanism by which
>> > the system is automatically suspended (i.e. put into a system-wide sleep state)
>> > whenever it's not doing useful work, called opportunistic suspend".
>> >
>> > "For this purpose introduce the suspend blockers framework allowing the
>> > kernel's power management subsystem to decide when it is desirable to suspend
>> > the system (i.e. when useful work is not being done).  Add an API that ..."
>> >
>>
>> PM: Opportunistic suspend support.
>>
>> Power management features present in the current mainline kernel are
>> insufficient to get maximum possible energy savings on some platforms,
>> such as Android, because low power states can only safely be entered
>> from idle.
>
> Do you mean CPU low-power states or system low-power states here?
>
I think either.

> I'd add more details here, because it may not be completely clear to the
> (interested) reader why entering these states only from idle affects the
> possibility to achieve maximum energy savings.  I _guess_ you mean that
> using idle is not sufficient, because there are so many wakeups on the
> systems in question that more savings are still possible.  Is that correct?
>
Yes, is this not what the next paragraph explains?

>> Suspend, in its current form, cannot be used, since wakeup
>> events that occur right after initiating suspend will not be processed
>> until another possibly unrelated event wake up the system again.
>
> I think the word "cannot" is too strong here.  I'd say "not suitable" instead

I don't think it is too strong, but I can change it.

> and I'd say what kind of wakeup events I meant more precisely (there are
> events that wake up a CPU from idle and events that wake up the system from
> suspend).

When I say wakeup events I mean events that do both. Is there another
term for this, or should I just add: "since wakeup events (events that
wake the CPU from idle and the system from suspend)..."

>
>> On some systems idle combined with runtime PM can enter the same power
>> state as suspend, but periodic wakeups increase the average power
>> consumption. Suspending the system also reduces the harm caused by
>> apps that never go idle. On other systems suspend can enter a much
>> lower power state than idle.
>>
>> To allow Android and similar platforms to save more energy than they
>> currently can save using the mainline kernel, we introduce a mechanism
>
> Just "introduce" without "we" works too.
>
>> by which the system is automatically suspended (i.e. put into a
>> system-wide sleep state) whenever it's not doing useful work, called
>> opportunistic suspend.
>
> I think we can address the Kevin's comment about "useful" and say "whenever
> it's only doing work that can be done later without noticeable effect on
> functionality".
>
>> For this purpose introduce the suspend blockers framework allowing the
>> kernel's power management subsystem to decide when it is desirable to
>> suspend the system (i.e. when useful work is not being done). Add an
>
> Perhaps remove the part in parens entirely.
>
>> API that that drivers can use to block opportunistic suspend. This is
>> needed to avoid losing wakeup events that occur right after suspend is
>> initiated.
>>
>> Adds /sys/power/policy that selects the behavior of /sys/power/state.
>> After setting the policy to opportunistic, writes to /sys/power/state
>> become non-blocking requests that specify which suspend state to enter
>> when no suspend blockers are active. A special state, "on", stops the
>> process by activating the "main" suspend blocker.
>
> ...
>
>> PM: suspend_block: Add driver to access suspend blockers from user-space
>>
>> Add a misc device, "suspend_blocker", that allows user-space processes
>> to block automatic suspend.
>>
>> Opening this device creates a suspend blocker that can be used by the
>> opener to prevent automatic suspend from occurring.  There are ioctls
>> provided for blocking and unblocking suspend and for giving the
>> suspend blocker a meaningful name.  Closing the device special file
>> causes the suspend blocker to be destroyed.
>>
>> For example, when select or poll indicates that input event are
>> available, this interface can be used by user space to block suspend
>> before it reads those events. This allows the input driver to release
>> its suspend blocker as soon as the event queue is empty. If user space
>> could not use a suspend blocker here the input driver would need to
>> delay the release of its suspend blocker until it knows (or assumes)
>> that user space has finished processing the events.
>>
>> By careful use of suspend blockers in drivers and user space system
>> code, one can arrange for the system to stay awake for extremely short
>> periods of time in reaction to events, rapidly returning to a fully
>> suspended state.
>
> That's fine by me.
>
> Thanks,
> Rafael
>



-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18 20:35               ` Arve Hjønnevåg
@ 2010-05-18 21:14                 ` Rafael J. Wysocki
  2010-05-18 22:21                   ` Arve Hjønnevåg
  0 siblings, 1 reply; 53+ messages in thread
From: Rafael J. Wysocki @ 2010-05-18 21:14 UTC (permalink / raw)
  To: Arve Hjønnevåg; +Cc: Brian Swetland, linux-pm, linux-kernel

On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
> >> On Mon, May 17, 2010 at 2:44 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> >> > On Monday 17 May 2010, Brian Swetland wrote:
> >> >> On Mon, May 17, 2010 at 1:40 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> >> >> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
> >> >> >>
...
> 
> > Now, to make it more "user-friendly", we can simply use
> > queue_delayed_work() with a reasonable delay instead of queue_work() to queue
> > the suspend work (the delay may be configurable via sysfs).
> >
> 
> I can add a delay (and the timeout support code does add a delay as an
> optimization) to the unknown wakeup case, but this does not fix the
> problem of a user turning on opportunistic suspend with a user space
> framework that does not use suspend blockers. If the kernel uses
> suspend blockers to make sure the wakeup event makes it to user space,
> but user space does not block suspend, then the system will suspend
> before the event is processed.

But the user can still manually write to /sys/power/state. :-)

Rafael

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18 20:47           ` Arve Hjønnevåg
@ 2010-05-18 21:48             ` Rafael J. Wysocki
  2010-05-18 22:03               ` Arve Hjønnevåg
  0 siblings, 1 reply; 53+ messages in thread
From: Rafael J. Wysocki @ 2010-05-18 21:48 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: linux-pm, linux-kernel, Greg KH, Mark Brown, Kevin Hilman,
	Alan Stern, Brian Swetland, Daniel Walker, Theodore Ts'o,
	Matthew Garrett

On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
> >> 2010/5/17 Rafael J. Wysocki <rjw@sisk.pl>:
> >> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
> >> >> 2010/5/14 Rafael J. Wysocki <rjw@sisk.pl>:
> >> >> > On Friday 14 May 2010, Arve Hjønnevåg wrote:
> >> >> >> This patch series adds a suspend-block api that provides the same
> >> >> >> functionality as the android wakelock api. This version has some
> >> >> >> changes from, or requested by, Rafael. The most notable changes are:
> >> >> >> - DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
> >> >> >>   for statically allocated suspend blockers.
> >> >> >> - suspend_blocker_destroy is now called suspend_blocker_unregister
> >> >> >> - The user space mandatory _INIT ioctl has been replaced with an
> >> >> >>   optional _SET_NAME ioctl.
> >> >> >>
> >> >> >> I kept the ack and reviewed by tags on two of the patches even though
> >> >> >> there were a few cosmetic changes.
> >> >> >
> >> >> > Thanks for the patches, I think they are in a pretty good shape now.
> >> >> >
> >> >> > That said, I'd like the changelogs to be a bit more descriptive, at least for
> >> >> > patch [1/8].  I think it should explain (in a few words) what the purpose of
> >> >> > the feature is and what problems it solves that generally a combination of
> >> >> > runtime PM and cpuidle is not suitable for in your opinion.  IOW, why you
> >> >> > think we need that feature.
> >> >> >
> >> >>
> >> >> How about:
> >> >>
> >> >> PM: Add opportunistic suspend support.
> >> >
> >> > "PM: Opportunistic suspend support" would be sufficient IMO.
> >> >
> >> > Now, I'd start with the motivation.  Like "Power management features present
> >> > in the current mainline kernel are insufficient to get maximum possible energy
> >> > savings on some platforms, such as Android, because ..." (here go explanations
> >> > why this is the case in your opinion).
> >> >
> >> > Next, "To allow Android and similar platforms to save more energy than they
> >> > currently can save using the mainline kernel, introduce a mechanism by which
> >> > the system is automatically suspended (i.e. put into a system-wide sleep state)
> >> > whenever it's not doing useful work, called opportunistic suspend".
> >> >
> >> > "For this purpose introduce the suspend blockers framework allowing the
> >> > kernel's power management subsystem to decide when it is desirable to suspend
> >> > the system (i.e. when useful work is not being done).  Add an API that ..."
> >> >
> >>
> >> PM: Opportunistic suspend support.
> >>
> >> Power management features present in the current mainline kernel are
> >> insufficient to get maximum possible energy savings on some platforms,
> >> such as Android, because low power states can only safely be entered
> >> from idle.
> >
> > Do you mean CPU low-power states or system low-power states here?
> >
> I think either.

The statement is not true for system low-power states (or sleep states),
because generally (ie. on many platforms) they aren't entered from idle.
Suspend is for entering them.

So, there is a difference and the explanation can go like this: "... to achieve
maximum energy savings one has to put all I/O devices and the CPU into
low-power states, but the CPU can only be put into a low-power state from
idle.  This, in turn, means that the CPU leaves the low-power state on
interrupts triggered by periodic timers and user space processes that use
polling.  It turns out, however, that many of these events causing the CPU to
leave the low-power state aren't essential for the desired system functionality
and from the power management point of view it would be better if they didn't
occur".

> > I'd add more details here, because it may not be completely clear to the
> > (interested) reader why entering these states only from idle affects the
> > possibility to achieve maximum energy savings.  I _guess_ you mean that
> > using idle is not sufficient, because there are so many wakeups on the
> > systems in question that more savings are still possible.  Is that correct?
> >
> Yes, is this not what the next paragraph explains?

Well, it doesn't explain that.  It explains why idle + runtime PM is generally
insufficient and is using that as an argument (at least in my view).

> >> Suspend, in its current form, cannot be used, since wakeup
> >> events that occur right after initiating suspend will not be processed
> >> until another possibly unrelated event wake up the system again.
> >
> > I think the word "cannot" is too strong here.  I'd say "not suitable" instead
> 
> I don't think it is too strong, but I can change it.
> 
> > and I'd say what kind of wakeup events I meant more precisely (there are
> > events that wake up a CPU from idle and events that wake up the system from
> > suspend).
> 
> When I say wakeup events I mean events that do both. Is there another
> term for this, or should I just add: "since wakeup events (events that
> wake the CPU from idle and the system from suspend)..."

Yes, that would clarify things IMO.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18 21:48             ` Rafael J. Wysocki
@ 2010-05-18 22:03               ` Arve Hjønnevåg
  2010-05-18 22:34                 ` Rafael J. Wysocki
  0 siblings, 1 reply; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-18 22:03 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-pm, linux-kernel, Greg KH, Mark Brown, Kevin Hilman,
	Alan Stern, Brian Swetland, Daniel Walker, Theodore Ts'o,
	Matthew Garrett

2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
>> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
>> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
>> >> 2010/5/17 Rafael J. Wysocki <rjw@sisk.pl>:
>> >> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
>> >> >> 2010/5/14 Rafael J. Wysocki <rjw@sisk.pl>:
>> >> >> > On Friday 14 May 2010, Arve Hjønnevåg wrote:
>> >> >> >> This patch series adds a suspend-block api that provides the same
>> >> >> >> functionality as the android wakelock api. This version has some
>> >> >> >> changes from, or requested by, Rafael. The most notable changes are:
>> >> >> >> - DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
>> >> >> >>   for statically allocated suspend blockers.
>> >> >> >> - suspend_blocker_destroy is now called suspend_blocker_unregister
>> >> >> >> - The user space mandatory _INIT ioctl has been replaced with an
>> >> >> >>   optional _SET_NAME ioctl.
>> >> >> >>
>> >> >> >> I kept the ack and reviewed by tags on two of the patches even though
>> >> >> >> there were a few cosmetic changes.
>> >> >> >
>> >> >> > Thanks for the patches, I think they are in a pretty good shape now.
>> >> >> >
>> >> >> > That said, I'd like the changelogs to be a bit more descriptive, at least for
>> >> >> > patch [1/8].  I think it should explain (in a few words) what the purpose of
>> >> >> > the feature is and what problems it solves that generally a combination of
>> >> >> > runtime PM and cpuidle is not suitable for in your opinion.  IOW, why you
>> >> >> > think we need that feature.
>> >> >> >
>> >> >>
>> >> >> How about:
>> >> >>
>> >> >> PM: Add opportunistic suspend support.
>> >> >
>> >> > "PM: Opportunistic suspend support" would be sufficient IMO.
>> >> >
>> >> > Now, I'd start with the motivation.  Like "Power management features present
>> >> > in the current mainline kernel are insufficient to get maximum possible energy
>> >> > savings on some platforms, such as Android, because ..." (here go explanations
>> >> > why this is the case in your opinion).
>> >> >
>> >> > Next, "To allow Android and similar platforms to save more energy than they
>> >> > currently can save using the mainline kernel, introduce a mechanism by which
>> >> > the system is automatically suspended (i.e. put into a system-wide sleep state)
>> >> > whenever it's not doing useful work, called opportunistic suspend".
>> >> >
>> >> > "For this purpose introduce the suspend blockers framework allowing the
>> >> > kernel's power management subsystem to decide when it is desirable to suspend
>> >> > the system (i.e. when useful work is not being done).  Add an API that ..."
>> >> >
>> >>
>> >> PM: Opportunistic suspend support.
>> >>
>> >> Power management features present in the current mainline kernel are
>> >> insufficient to get maximum possible energy savings on some platforms,
>> >> such as Android, because low power states can only safely be entered
>> >> from idle.
>> >
>> > Do you mean CPU low-power states or system low-power states here?
>> >
>> I think either.
>
> The statement is not true for system low-power states (or sleep states),
> because generally (ie. on many platforms) they aren't entered from idle.
> Suspend is for entering them.
>
I don't think that makes my statement false. If you can only safely
enter low power states from idle, but some low power states cannot be
entered from idle, then it follows that you cannot safely enter those
low power states.

> So, there is a difference and the explanation can go like this: "... to achieve
> maximum energy savings one has to put all I/O devices and the CPU into
> low-power states, but the CPU can only be put into a low-power state from
> idle.  This, in turn, means that the CPU leaves the low-power state on
> interrupts triggered by periodic timers and user space processes that use
> polling.  It turns out, however, that many of these events causing the CPU to
> leave the low-power state aren't essential for the desired system functionality
> and from the power management point of view it would be better if they didn't
> occur".

This only explain why we still want to use suspend on systems that can
enter the same power states from idle and suspend.

>
>> > I'd add more details here, because it may not be completely clear to the
>> > (interested) reader why entering these states only from idle affects the
>> > possibility to achieve maximum energy savings.  I _guess_ you mean that
>> > using idle is not sufficient, because there are so many wakeups on the
>> > systems in question that more savings are still possible.  Is that correct?
>> >
>> Yes, is this not what the next paragraph explains?
>
> Well, it doesn't explain that.  It explains why idle + runtime PM is generally
> insufficient and is using that as an argument (at least in my view).
>
>> >> Suspend, in its current form, cannot be used, since wakeup
>> >> events that occur right after initiating suspend will not be processed
>> >> until another possibly unrelated event wake up the system again.
>> >
>> > I think the word "cannot" is too strong here.  I'd say "not suitable" instead
>>
>> I don't think it is too strong, but I can change it.
>>
>> > and I'd say what kind of wakeup events I meant more precisely (there are
>> > events that wake up a CPU from idle and events that wake up the system from
>> > suspend).
>>
>> When I say wakeup events I mean events that do both. Is there another
>> term for this, or should I just add: "since wakeup events (events that
>> wake the CPU from idle and the system from suspend)..."
>
> Yes, that would clarify things IMO.
>
> Thanks,
> Rafael
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>



-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18 18:52           ` Rafael J. Wysocki
@ 2010-05-18 22:04             ` Kevin Hilman
  2010-05-18 22:29               ` Rafael J. Wysocki
  0 siblings, 1 reply; 53+ messages in thread
From: Kevin Hilman @ 2010-05-18 22:04 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Arve Hjønnevåg, linux-pm, linux-kernel, Greg KH,
	Mark Brown, Alan Stern, Brian Swetland, Daniel Walker,
	Theodore Ts'o, Matthew Garrett

"Rafael J. Wysocki" <rjw@sisk.pl> writes:

> On Tuesday 18 May 2010, Kevin Hilman wrote:
>> Arve Hjønnevåg <arve@android.com> writes:
>> 
>> >
>> > PM: Opportunistic suspend support.
>> >
>> > Power management features present in the current mainline kernel are
>> > insufficient to get maximum possible energy savings on some platforms,
>> > such as Android, because low power states can only safely be entered
>> > from idle.  Suspend, in its current form, cannot be used, since wakeup
>> > events that occur right after initiating suspend will not be processed
>> > until another possibly unrelated event wake up the system again.
>> 
>> I think the problems with wakeups in the current suspend path need to
>> be described in more detail.  In particular, why check_wakeup_irqs()
>> is not enough etc.
>
> That one is really easy.: because some (the majority of?) architectures
> don't even implement it.

OK, then this problem will still in traditional suspend even after
this series, so calling it out as a the problem to be solved but not
fixing it doesn't seem right.

This problem needs an independent fix, namely implementing
check_wakeup_irqs().

That being said, what exactly is there for architectures to implement
for check_wakeup_irqs()?  IIUC, this all handled by genirq as long as
deferred disable (now the default) is used?

I suspect the platforms that Android currently cares about already
have this functionality.  At least OMAP does already.

>> > On some systems idle combined with runtime PM can enter the same power
>> > state as suspend, but periodic wakeups increase the average power
>> > consumption. Suspending the system also reduces the harm caused by
>> > apps that never go idle. On other systems suspend can enter a much
>> > lower power state than idle.
>> >
>> > To allow Android and similar platforms to save more energy than they
>> > currently can save using the mainline kernel, we introduce a mechanism
>> > by which the system is automatically suspended (i.e. put into a
>> > system-wide sleep state) whenever it's not doing useful work, called
>> > opportunistic suspend.
>> 
>> A definition of "useful work" here would provide clarity and would
>> also help clarify by what criteria other on-going work is determined
>> to be not useful.
>
> Probably "useful" is not the right word here.  I guess it's more like
> "work that can be deferred without visible impact on functionality".

OK, then a definition of "visible impact on functionality" should be
provided and the critera for determining that.

I know this sounds like splitting hairs, but what I'm getting at is
that this series implements a brand new method for making decisions
about when the system is idle.  That fact should be clearly stated and
the criteria for making this decision should be clearly described.

Kevin

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18 21:14                 ` Rafael J. Wysocki
@ 2010-05-18 22:21                   ` Arve Hjønnevåg
  2010-05-18 22:56                     ` Rafael J. Wysocki
  0 siblings, 1 reply; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-18 22:21 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Brian Swetland, linux-pm, linux-kernel

2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
>> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
>> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
>> >> On Mon, May 17, 2010 at 2:44 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
>> >> > On Monday 17 May 2010, Brian Swetland wrote:
>> >> >> On Mon, May 17, 2010 at 1:40 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
>> >> >> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
>> >> >> >>
> ...
>>
>> > Now, to make it more "user-friendly", we can simply use
>> > queue_delayed_work() with a reasonable delay instead of queue_work() to queue
>> > the suspend work (the delay may be configurable via sysfs).
>> >
>>
>> I can add a delay (and the timeout support code does add a delay as an
>> optimization) to the unknown wakeup case, but this does not fix the
>> problem of a user turning on opportunistic suspend with a user space
>> framework that does not use suspend blockers. If the kernel uses
>> suspend blockers to make sure the wakeup event makes it to user space,
>> but user space does not block suspend, then the system will suspend
>> before the event is processed.
>
> But the user can still manually write to /sys/power/state. :-)
>

Does adding or removing a delay change this? It seems in only changes
how quickly the user can finish that write.

I'm not convinced adding a configurable delay here is necessary. Once
the driver that enabled the wakeup event has been updated to block
suspend until this event gets to user space, then this delay will
never be triggered. The kernel cannot tell the difference between a
user enabling opportunistic suspend but not wanting it and
opportunistic suspend aware user space code deciding that this wakeup
event should be ignored.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18 22:04             ` Kevin Hilman
@ 2010-05-18 22:29               ` Rafael J. Wysocki
  0 siblings, 0 replies; 53+ messages in thread
From: Rafael J. Wysocki @ 2010-05-18 22:29 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Arve Hjønnevåg, linux-pm, linux-kernel, Greg KH,
	Mark Brown, Alan Stern, Brian Swetland, Daniel Walker,
	Theodore Ts'o, Matthew Garrett

On Wednesday 19 May 2010, Kevin Hilman wrote:
> "Rafael J. Wysocki" <rjw@sisk.pl> writes:
> 
> > On Tuesday 18 May 2010, Kevin Hilman wrote:
> >> Arve Hjønnevåg <arve@android.com> writes:
> >> 
> >> >
> >> > PM: Opportunistic suspend support.
> >> >
> >> > Power management features present in the current mainline kernel are
> >> > insufficient to get maximum possible energy savings on some platforms,
> >> > such as Android, because low power states can only safely be entered
> >> > from idle.  Suspend, in its current form, cannot be used, since wakeup
> >> > events that occur right after initiating suspend will not be processed
> >> > until another possibly unrelated event wake up the system again.
> >> 
> >> I think the problems with wakeups in the current suspend path need to
> >> be described in more detail.  In particular, why check_wakeup_irqs()
> >> is not enough etc.
> >
> > That one is really easy.: because some (the majority of?) architectures
> > don't even implement it.
> 
> OK, then this problem will still in traditional suspend even after
> this series, so calling it out as a the problem to be solved but not
> fixing it doesn't seem right.
> 
> This problem needs an independent fix, namely implementing
> check_wakeup_irqs().

No, it is not.  There's nothing like wake-up interrupts on (ACPI-based) x86 PCs.
 
> That being said, what exactly is there for architectures to implement
> for check_wakeup_irqs()?  IIUC, this all handled by genirq as long as
> deferred disable (now the default) is used?

No.  Wakeup IRQs cause the system to wake up from sleep states.  On a PC
the only interrupts that can do that are PCIe root port PME interrupts, but
they are not really "device" interrupts (ie. they come from a source that is
different from a device signaling wakeup).

> I suspect the platforms that Android currently cares about already
> have this functionality.  At least OMAP does already.

ISTR there is an x86 Android port, so not all of them.  Although that really
doesn't matter.

> >> > On some systems idle combined with runtime PM can enter the same power
> >> > state as suspend, but periodic wakeups increase the average power
> >> > consumption. Suspending the system also reduces the harm caused by
> >> > apps that never go idle. On other systems suspend can enter a much
> >> > lower power state than idle.
> >> >
> >> > To allow Android and similar platforms to save more energy than they
> >> > currently can save using the mainline kernel, we introduce a mechanism
> >> > by which the system is automatically suspended (i.e. put into a
> >> > system-wide sleep state) whenever it's not doing useful work, called
> >> > opportunistic suspend.
> >> 
> >> A definition of "useful work" here would provide clarity and would
> >> also help clarify by what criteria other on-going work is determined
> >> to be not useful.
> >
> > Probably "useful" is not the right word here.  I guess it's more like
> > "work that can be deferred without visible impact on functionality".
> 
> OK, then a definition of "visible impact on functionality" should be
> provided and the critera for determining that.
> 
> I know this sounds like splitting hairs,

Yes, it does.

> but what I'm getting at is that this series implements a brand new method
> for making decisions about when the system is idle.

Since we are splitting hairs, I'd be rather cautious about the word "idle".
It would be safer to say "when the system is not doing anything the user
really cares about at the moment and therefore it may be suspended".

That actually is the whole point of the patch series.

> That fact should be clearly stated and the criteria for making this decision
> should be clearly described.

Well, suspend blockers are the tool to define the criteria.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18 22:03               ` Arve Hjønnevåg
@ 2010-05-18 22:34                 ` Rafael J. Wysocki
  2010-05-18 22:52                   ` Arve Hjønnevåg
  0 siblings, 1 reply; 53+ messages in thread
From: Rafael J. Wysocki @ 2010-05-18 22:34 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: linux-pm, linux-kernel, Greg KH, Mark Brown, Kevin Hilman,
	Alan Stern, Brian Swetland, Daniel Walker, Theodore Ts'o,
	Matthew Garrett

On Wednesday 19 May 2010, Arve Hjønnevåg wrote:
> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
> >> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> >> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
> >> >> 2010/5/17 Rafael J. Wysocki <rjw@sisk.pl>:
> >> >> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
> >> >> >> 2010/5/14 Rafael J. Wysocki <rjw@sisk.pl>:
> >> >> >> > On Friday 14 May 2010, Arve Hjønnevåg wrote:
> >> >> >> >> This patch series adds a suspend-block api that provides the same
> >> >> >> >> functionality as the android wakelock api. This version has some
> >> >> >> >> changes from, or requested by, Rafael. The most notable changes are:
> >> >> >> >> - DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
> >> >> >> >>   for statically allocated suspend blockers.
> >> >> >> >> - suspend_blocker_destroy is now called suspend_blocker_unregister
> >> >> >> >> - The user space mandatory _INIT ioctl has been replaced with an
> >> >> >> >>   optional _SET_NAME ioctl.
> >> >> >> >>
> >> >> >> >> I kept the ack and reviewed by tags on two of the patches even though
> >> >> >> >> there were a few cosmetic changes.
> >> >> >> >
> >> >> >> > Thanks for the patches, I think they are in a pretty good shape now.
> >> >> >> >
> >> >> >> > That said, I'd like the changelogs to be a bit more descriptive, at least for
> >> >> >> > patch [1/8].  I think it should explain (in a few words) what the purpose of
> >> >> >> > the feature is and what problems it solves that generally a combination of
> >> >> >> > runtime PM and cpuidle is not suitable for in your opinion.  IOW, why you
> >> >> >> > think we need that feature.
> >> >> >> >
> >> >> >>
> >> >> >> How about:
> >> >> >>
> >> >> >> PM: Add opportunistic suspend support.
> >> >> >
> >> >> > "PM: Opportunistic suspend support" would be sufficient IMO.
> >> >> >
> >> >> > Now, I'd start with the motivation.  Like "Power management features present
> >> >> > in the current mainline kernel are insufficient to get maximum possible energy
> >> >> > savings on some platforms, such as Android, because ..." (here go explanations
> >> >> > why this is the case in your opinion).
> >> >> >
> >> >> > Next, "To allow Android and similar platforms to save more energy than they
> >> >> > currently can save using the mainline kernel, introduce a mechanism by which
> >> >> > the system is automatically suspended (i.e. put into a system-wide sleep state)
> >> >> > whenever it's not doing useful work, called opportunistic suspend".
> >> >> >
> >> >> > "For this purpose introduce the suspend blockers framework allowing the
> >> >> > kernel's power management subsystem to decide when it is desirable to suspend
> >> >> > the system (i.e. when useful work is not being done).  Add an API that ..."
> >> >> >
> >> >>
> >> >> PM: Opportunistic suspend support.
> >> >>
> >> >> Power management features present in the current mainline kernel are
> >> >> insufficient to get maximum possible energy savings on some platforms,
> >> >> such as Android, because low power states can only safely be entered
> >> >> from idle.
> >> >
> >> > Do you mean CPU low-power states or system low-power states here?
> >> >
> >> I think either.
> >
> > The statement is not true for system low-power states (or sleep states),
> > because generally (ie. on many platforms) they aren't entered from idle.
> > Suspend is for entering them.
> >
> I don't think that makes my statement false. If you can only safely
> enter low power states from idle, but some low power states cannot be
> entered from idle, then it follows that you cannot safely enter those
> low power states.

Define "safely", then.

> > So, there is a difference and the explanation can go like this: "... to achieve
> > maximum energy savings one has to put all I/O devices and the CPU into
> > low-power states, but the CPU can only be put into a low-power state from
> > idle.  This, in turn, means that the CPU leaves the low-power state on
> > interrupts triggered by periodic timers and user space processes that use
> > polling.  It turns out, however, that many of these events causing the CPU to
> > leave the low-power state aren't essential for the desired system functionality
> > and from the power management point of view it would be better if they didn't
> > occur".
> 
> This only explain why we still want to use suspend on systems that can
> enter the same power states from idle and suspend.

Sorry, I'm confused now.  Isn't that why you do that on Android?

AFACS, your hardware is capable of doing that, isn't it?

Rafael

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18 22:34                 ` Rafael J. Wysocki
@ 2010-05-18 22:52                   ` Arve Hjønnevåg
  2010-05-18 23:19                     ` Rafael J. Wysocki
  0 siblings, 1 reply; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-18 22:52 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-pm, linux-kernel, Greg KH, Mark Brown, Kevin Hilman,
	Alan Stern, Brian Swetland, Daniel Walker, Theodore Ts'o,
	Matthew Garrett

2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> On Wednesday 19 May 2010, Arve Hjønnevåg wrote:
>> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
>> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
>> >> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
>> >> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
>> >> >> 2010/5/17 Rafael J. Wysocki <rjw@sisk.pl>:
>> >> >> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
>> >> >> >> 2010/5/14 Rafael J. Wysocki <rjw@sisk.pl>:
>> >> >> >> > On Friday 14 May 2010, Arve Hjønnevåg wrote:
>> >> >> >> >> This patch series adds a suspend-block api that provides the same
>> >> >> >> >> functionality as the android wakelock api. This version has some
>> >> >> >> >> changes from, or requested by, Rafael. The most notable changes are:
>> >> >> >> >> - DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
>> >> >> >> >>   for statically allocated suspend blockers.
>> >> >> >> >> - suspend_blocker_destroy is now called suspend_blocker_unregister
>> >> >> >> >> - The user space mandatory _INIT ioctl has been replaced with an
>> >> >> >> >>   optional _SET_NAME ioctl.
>> >> >> >> >>
>> >> >> >> >> I kept the ack and reviewed by tags on two of the patches even though
>> >> >> >> >> there were a few cosmetic changes.
>> >> >> >> >
>> >> >> >> > Thanks for the patches, I think they are in a pretty good shape now.
>> >> >> >> >
>> >> >> >> > That said, I'd like the changelogs to be a bit more descriptive, at least for
>> >> >> >> > patch [1/8].  I think it should explain (in a few words) what the purpose of
>> >> >> >> > the feature is and what problems it solves that generally a combination of
>> >> >> >> > runtime PM and cpuidle is not suitable for in your opinion.  IOW, why you
>> >> >> >> > think we need that feature.
>> >> >> >> >
>> >> >> >>
>> >> >> >> How about:
>> >> >> >>
>> >> >> >> PM: Add opportunistic suspend support.
>> >> >> >
>> >> >> > "PM: Opportunistic suspend support" would be sufficient IMO.
>> >> >> >
>> >> >> > Now, I'd start with the motivation.  Like "Power management features present
>> >> >> > in the current mainline kernel are insufficient to get maximum possible energy
>> >> >> > savings on some platforms, such as Android, because ..." (here go explanations
>> >> >> > why this is the case in your opinion).
>> >> >> >
>> >> >> > Next, "To allow Android and similar platforms to save more energy than they
>> >> >> > currently can save using the mainline kernel, introduce a mechanism by which
>> >> >> > the system is automatically suspended (i.e. put into a system-wide sleep state)
>> >> >> > whenever it's not doing useful work, called opportunistic suspend".
>> >> >> >
>> >> >> > "For this purpose introduce the suspend blockers framework allowing the
>> >> >> > kernel's power management subsystem to decide when it is desirable to suspend
>> >> >> > the system (i.e. when useful work is not being done).  Add an API that ..."
>> >> >> >
>> >> >>
>> >> >> PM: Opportunistic suspend support.
>> >> >>
>> >> >> Power management features present in the current mainline kernel are
>> >> >> insufficient to get maximum possible energy savings on some platforms,
>> >> >> such as Android, because low power states can only safely be entered
>> >> >> from idle.
>> >> >
>> >> > Do you mean CPU low-power states or system low-power states here?
>> >> >
>> >> I think either.
>> >
>> > The statement is not true for system low-power states (or sleep states),
>> > because generally (ie. on many platforms) they aren't entered from idle.
>> > Suspend is for entering them.
>> >
>> I don't think that makes my statement false. If you can only safely
>> enter low power states from idle, but some low power states cannot be
>> entered from idle, then it follows that you cannot safely enter those
>> low power states.
>
> Define "safely", then.
>
OK. Is this clearer:

Power management features present in the current mainline kernel are
insufficient to get maximum possible energy savings on some platforms,
such as Android, because some wakeup events must work at all times
which means that low power states can only safely be entered from idle.
Suspend, in its current form, cannot be used, since wakeup events that
occur right after initiating suspend will not be processed until another
possibly unrelated event wake up the system again.


>> > So, there is a difference and the explanation can go like this: "... to achieve
>> > maximum energy savings one has to put all I/O devices and the CPU into
>> > low-power states, but the CPU can only be put into a low-power state from
>> > idle.  This, in turn, means that the CPU leaves the low-power state on
>> > interrupts triggered by periodic timers and user space processes that use
>> > polling.  It turns out, however, that many of these events causing the CPU to
>> > leave the low-power state aren't essential for the desired system functionality
>> > and from the power management point of view it would be better if they didn't
>> > occur".
>>
>> This only explain why we still want to use suspend on systems that can
>> enter the same power states from idle and suspend.
>
> Sorry, I'm confused now.  Isn't that why you do that on Android?
>

Yes, but it is not the only reason to use opportunistic support. It is
way more important to have opportunistic suspend support if the
hardware can enter lower power states from suspend than idle.

> AFACS, your hardware is capable of doing that, isn't it?
>

The current hardware, yes, the hardware we started with, no.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18 22:21                   ` Arve Hjønnevåg
@ 2010-05-18 22:56                     ` Rafael J. Wysocki
  2010-05-18 23:06                       ` Arve Hjønnevåg
  0 siblings, 1 reply; 53+ messages in thread
From: Rafael J. Wysocki @ 2010-05-18 22:56 UTC (permalink / raw)
  To: Arve Hjønnevåg; +Cc: Brian Swetland, linux-pm, linux-kernel

On Wednesday 19 May 2010, Arve Hjønnevåg wrote:
> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
> >> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> >> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
> >> >> On Mon, May 17, 2010 at 2:44 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> >> >> > On Monday 17 May 2010, Brian Swetland wrote:
> >> >> >> On Mon, May 17, 2010 at 1:40 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> >> >> >> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
> >> >> >> >>
> > ...
> >>
> >> > Now, to make it more "user-friendly", we can simply use
> >> > queue_delayed_work() with a reasonable delay instead of queue_work() to queue
> >> > the suspend work (the delay may be configurable via sysfs).
> >> >
> >>
> >> I can add a delay (and the timeout support code does add a delay as an
> >> optimization) to the unknown wakeup case, but this does not fix the
> >> problem of a user turning on opportunistic suspend with a user space
> >> framework that does not use suspend blockers. If the kernel uses
> >> suspend blockers to make sure the wakeup event makes it to user space,
> >> but user space does not block suspend, then the system will suspend
> >> before the event is processed.
> >
> > But the user can still manually write to /sys/power/state. :-)
> >
> 
> Does adding or removing a delay change this? It seems in only changes
> how quickly the user can finish that write.

Yes, but that should allow the user to avoid rebooting the system if he does
the "wrong thing".

> I'm not convinced adding a configurable delay here is necessary.

No, it's not, but it would be useful in some cases IMO.  Pretty much the same
way your debug features are useful.

> Once the driver that enabled the wakeup event has been updated to block
> suspend until this event gets to user space, then this delay will
> never be triggered. The kernel cannot tell the difference between a
> user enabling opportunistic suspend but not wanting it and
> opportunistic suspend aware user space code deciding that this wakeup
> event should be ignored.

The point is, if there's a delay, it may be too aggressive for some users and
too conservative for some other users, so it makes sense to provide a means
to adjust it to the user's needs.

Rafael

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18 22:56                     ` Rafael J. Wysocki
@ 2010-05-18 23:06                       ` Arve Hjønnevåg
  2010-05-19 20:40                         ` Rafael J. Wysocki
  0 siblings, 1 reply; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-18 23:06 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Brian Swetland, linux-pm, linux-kernel

2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> On Wednesday 19 May 2010, Arve Hjønnevåg wrote:
>> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
>> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
>> >> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
>> >> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
>> >> >> On Mon, May 17, 2010 at 2:44 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
>> >> >> > On Monday 17 May 2010, Brian Swetland wrote:
>> >> >> >> On Mon, May 17, 2010 at 1:40 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
>> >> >> >> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
>> >> >> >> >>
>> > ...
>> >>
>> >> > Now, to make it more "user-friendly", we can simply use
>> >> > queue_delayed_work() with a reasonable delay instead of queue_work() to queue
>> >> > the suspend work (the delay may be configurable via sysfs).
>> >> >
>> >>
>> >> I can add a delay (and the timeout support code does add a delay as an
>> >> optimization) to the unknown wakeup case, but this does not fix the
>> >> problem of a user turning on opportunistic suspend with a user space
>> >> framework that does not use suspend blockers. If the kernel uses
>> >> suspend blockers to make sure the wakeup event makes it to user space,
>> >> but user space does not block suspend, then the system will suspend
>> >> before the event is processed.
>> >
>> > But the user can still manually write to /sys/power/state. :-)
>> >
>>
>> Does adding or removing a delay change this? It seems in only changes
>> how quickly the user can finish that write.
>
> Yes, but that should allow the user to avoid rebooting the system if he does
> the "wrong thing".
>
>> I'm not convinced adding a configurable delay here is necessary.
>
> No, it's not, but it would be useful in some cases IMO.  Pretty much the same
> way your debug features are useful.
>
>> Once the driver that enabled the wakeup event has been updated to block
>> suspend until this event gets to user space, then this delay will
>> never be triggered. The kernel cannot tell the difference between a
>> user enabling opportunistic suspend but not wanting it and
>> opportunistic suspend aware user space code deciding that this wakeup
>> event should be ignored.
>
> The point is, if there's a delay, it may be too aggressive for some users and
> too conservative for some other users, so it makes sense to provide a means
> to adjust it to the user's needs.
>

My point is that the delay will not be used at all if the driver uses
a suspend blocker (like it should). Why add a configuration option for
opportunistic suspend that only works when the driver does not support
opportunistic suspend.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18 22:52                   ` Arve Hjønnevåg
@ 2010-05-18 23:19                     ` Rafael J. Wysocki
  2010-05-18 23:42                       ` Arve Hjønnevåg
  0 siblings, 1 reply; 53+ messages in thread
From: Rafael J. Wysocki @ 2010-05-18 23:19 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: linux-pm, linux-kernel, Greg KH, Mark Brown, Kevin Hilman,
	Alan Stern, Brian Swetland, Daniel Walker, Theodore Ts'o,
	Matthew Garrett

On Wednesday 19 May 2010, Arve Hjønnevåg wrote:
> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Wednesday 19 May 2010, Arve Hjønnevåg wrote:
> >> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> >> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
> >> >> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> >> >> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
> >> >> >> 2010/5/17 Rafael J. Wysocki <rjw@sisk.pl>:
> >> >> >> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
> >> >> >> >> 2010/5/14 Rafael J. Wysocki <rjw@sisk.pl>:
> >> >> >> >> > On Friday 14 May 2010, Arve Hjønnevåg wrote:
> >> >> >> >> >> This patch series adds a suspend-block api that provides the same
> >> >> >> >> >> functionality as the android wakelock api. This version has some
> >> >> >> >> >> changes from, or requested by, Rafael. The most notable changes are:
> >> >> >> >> >> - DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
> >> >> >> >> >>   for statically allocated suspend blockers.
> >> >> >> >> >> - suspend_blocker_destroy is now called suspend_blocker_unregister
> >> >> >> >> >> - The user space mandatory _INIT ioctl has been replaced with an
> >> >> >> >> >>   optional _SET_NAME ioctl.
> >> >> >> >> >>
> >> >> >> >> >> I kept the ack and reviewed by tags on two of the patches even though
> >> >> >> >> >> there were a few cosmetic changes.
> >> >> >> >> >
> >> >> >> >> > Thanks for the patches, I think they are in a pretty good shape now.
> >> >> >> >> >
> >> >> >> >> > That said, I'd like the changelogs to be a bit more descriptive, at least for
> >> >> >> >> > patch [1/8].  I think it should explain (in a few words) what the purpose of
> >> >> >> >> > the feature is and what problems it solves that generally a combination of
> >> >> >> >> > runtime PM and cpuidle is not suitable for in your opinion.  IOW, why you
> >> >> >> >> > think we need that feature.
> >> >> >> >> >
> >> >> >> >>
> >> >> >> >> How about:
> >> >> >> >>
> >> >> >> >> PM: Add opportunistic suspend support.
> >> >> >> >
> >> >> >> > "PM: Opportunistic suspend support" would be sufficient IMO.
> >> >> >> >
> >> >> >> > Now, I'd start with the motivation.  Like "Power management features present
> >> >> >> > in the current mainline kernel are insufficient to get maximum possible energy
> >> >> >> > savings on some platforms, such as Android, because ..." (here go explanations
> >> >> >> > why this is the case in your opinion).
> >> >> >> >
> >> >> >> > Next, "To allow Android and similar platforms to save more energy than they
> >> >> >> > currently can save using the mainline kernel, introduce a mechanism by which
> >> >> >> > the system is automatically suspended (i.e. put into a system-wide sleep state)
> >> >> >> > whenever it's not doing useful work, called opportunistic suspend".
> >> >> >> >
> >> >> >> > "For this purpose introduce the suspend blockers framework allowing the
> >> >> >> > kernel's power management subsystem to decide when it is desirable to suspend
> >> >> >> > the system (i.e. when useful work is not being done).  Add an API that ..."
> >> >> >> >
> >> >> >>
> >> >> >> PM: Opportunistic suspend support.
> >> >> >>
> >> >> >> Power management features present in the current mainline kernel are
> >> >> >> insufficient to get maximum possible energy savings on some platforms,
> >> >> >> such as Android, because low power states can only safely be entered
> >> >> >> from idle.
> >> >> >
> >> >> > Do you mean CPU low-power states or system low-power states here?
> >> >> >
> >> >> I think either.
> >> >
> >> > The statement is not true for system low-power states (or sleep states),
> >> > because generally (ie. on many platforms) they aren't entered from idle.
> >> > Suspend is for entering them.
> >> >
> >> I don't think that makes my statement false. If you can only safely
> >> enter low power states from idle, but some low power states cannot be
> >> entered from idle, then it follows that you cannot safely enter those
> >> low power states.
> >
> > Define "safely", then.
> >
> OK. Is this clearer:

Not really.

> Power management features present in the current mainline kernel are
> insufficient to get maximum possible energy savings on some platforms,
> such as Android, because some wakeup events must work at all times
> which means that low power states can only safely be entered from idle.

It's not clear what you mean by "some wakeup events must work at all times"
and what "safely" means.

> Suspend, in its current form, cannot be used, since wakeup events that
> occur right after initiating suspend will not be processed until another
> possibly unrelated event wake up the system again.

Well, I _guess_ I know what you're trying to say, but I'm not sure if that's
the core of the problem the patchset is supposed to address.

The problem, as I see it, is really two-fold.

First, to save as much energy as reasonably possible you need to put everything
except for memory (ie. I/O devices and CPUs) into low-power states and let that
stay in these low-power states for as long as reasonably possible, right?

Second, you need the system to _always_ respond to some _specific_ events
regardless of its current state, correct?

Now, at present, we can put I/O devices and the CPU into low-power states
at the same time in two ways: (1) by using runtime PM and cpuidle and (2) by
suspending the system.  Unfortunately, none of these approaches is ideal,
because (1) is vulnerable to periodic timers and polling apps (and CPU-bound
apps) and (2) doesn't guarantee that all events you care about will be
responded to.

The proposed solution is to use suspend with an additional mechanism that
will prevent the events that have to be responded to from being lost.  This
additional mechanism is suspend blockers.

Is this correct?

> >> > So, there is a difference and the explanation can go like this: "... to achieve
> >> > maximum energy savings one has to put all I/O devices and the CPU into
> >> > low-power states, but the CPU can only be put into a low-power state from
> >> > idle.  This, in turn, means that the CPU leaves the low-power state on
> >> > interrupts triggered by periodic timers and user space processes that use
> >> > polling.  It turns out, however, that many of these events causing the CPU to
> >> > leave the low-power state aren't essential for the desired system functionality
> >> > and from the power management point of view it would be better if they didn't
> >> > occur".
> >>
> >> This only explain why we still want to use suspend on systems that can
> >> enter the same power states from idle and suspend.
> >
> > Sorry, I'm confused now.  Isn't that why you do that on Android?
> >
> 
> Yes, but it is not the only reason to use opportunistic support. It is
> way more important to have opportunistic suspend support if the
> hardware can enter lower power states from suspend than idle.

Sure, but you can add something like "There also are systems where some
devices cannot be put into low-power states without suspending the entire
system (or the low-power states available to them without suspending the
entire system are substantially shallower than the low-power states they are
put into when the entire system is suspended), so the system have to be
suspended as a whole to achieve the maximum energy savings".

Rafael

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18 23:19                     ` Rafael J. Wysocki
@ 2010-05-18 23:42                       ` Arve Hjønnevåg
  2010-05-19 20:39                         ` Rafael J. Wysocki
  0 siblings, 1 reply; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-18 23:42 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-pm, linux-kernel, Greg KH, Mark Brown, Kevin Hilman,
	Alan Stern, Brian Swetland, Daniel Walker, Theodore Ts'o,
	Matthew Garrett

2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> On Wednesday 19 May 2010, Arve Hjønnevåg wrote:
>> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
>> > On Wednesday 19 May 2010, Arve Hjønnevåg wrote:
>> >> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
>> >> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
>> >> >> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
>> >> >> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
>> >> >> >> 2010/5/17 Rafael J. Wysocki <rjw@sisk.pl>:
>> >> >> >> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
>> >> >> >> >> 2010/5/14 Rafael J. Wysocki <rjw@sisk.pl>:
>> >> >> >> >> > On Friday 14 May 2010, Arve Hjønnevåg wrote:
>> >> >> >> >> >> This patch series adds a suspend-block api that provides the same
>> >> >> >> >> >> functionality as the android wakelock api. This version has some
>> >> >> >> >> >> changes from, or requested by, Rafael. The most notable changes are:
>> >> >> >> >> >> - DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
>> >> >> >> >> >>   for statically allocated suspend blockers.
>> >> >> >> >> >> - suspend_blocker_destroy is now called suspend_blocker_unregister
>> >> >> >> >> >> - The user space mandatory _INIT ioctl has been replaced with an
>> >> >> >> >> >>   optional _SET_NAME ioctl.
>> >> >> >> >> >>
>> >> >> >> >> >> I kept the ack and reviewed by tags on two of the patches even though
>> >> >> >> >> >> there were a few cosmetic changes.
>> >> >> >> >> >
>> >> >> >> >> > Thanks for the patches, I think they are in a pretty good shape now.
>> >> >> >> >> >
>> >> >> >> >> > That said, I'd like the changelogs to be a bit more descriptive, at least for
>> >> >> >> >> > patch [1/8].  I think it should explain (in a few words) what the purpose of
>> >> >> >> >> > the feature is and what problems it solves that generally a combination of
>> >> >> >> >> > runtime PM and cpuidle is not suitable for in your opinion.  IOW, why you
>> >> >> >> >> > think we need that feature.
>> >> >> >> >> >
>> >> >> >> >>
>> >> >> >> >> How about:
>> >> >> >> >>
>> >> >> >> >> PM: Add opportunistic suspend support.
>> >> >> >> >
>> >> >> >> > "PM: Opportunistic suspend support" would be sufficient IMO.
>> >> >> >> >
>> >> >> >> > Now, I'd start with the motivation.  Like "Power management features present
>> >> >> >> > in the current mainline kernel are insufficient to get maximum possible energy
>> >> >> >> > savings on some platforms, such as Android, because ..." (here go explanations
>> >> >> >> > why this is the case in your opinion).
>> >> >> >> >
>> >> >> >> > Next, "To allow Android and similar platforms to save more energy than they
>> >> >> >> > currently can save using the mainline kernel, introduce a mechanism by which
>> >> >> >> > the system is automatically suspended (i.e. put into a system-wide sleep state)
>> >> >> >> > whenever it's not doing useful work, called opportunistic suspend".
>> >> >> >> >
>> >> >> >> > "For this purpose introduce the suspend blockers framework allowing the
>> >> >> >> > kernel's power management subsystem to decide when it is desirable to suspend
>> >> >> >> > the system (i.e. when useful work is not being done).  Add an API that ..."
>> >> >> >> >
>> >> >> >>
>> >> >> >> PM: Opportunistic suspend support.
>> >> >> >>
>> >> >> >> Power management features present in the current mainline kernel are
>> >> >> >> insufficient to get maximum possible energy savings on some platforms,
>> >> >> >> such as Android, because low power states can only safely be entered
>> >> >> >> from idle.
>> >> >> >
>> >> >> > Do you mean CPU low-power states or system low-power states here?
>> >> >> >
>> >> >> I think either.
>> >> >
>> >> > The statement is not true for system low-power states (or sleep states),
>> >> > because generally (ie. on many platforms) they aren't entered from idle.
>> >> > Suspend is for entering them.
>> >> >
>> >> I don't think that makes my statement false. If you can only safely
>> >> enter low power states from idle, but some low power states cannot be
>> >> entered from idle, then it follows that you cannot safely enter those
>> >> low power states.
>> >
>> > Define "safely", then.
>> >
>> OK. Is this clearer:
>
> Not really.
>
>> Power management features present in the current mainline kernel are
>> insufficient to get maximum possible energy savings on some platforms,
>> such as Android, because some wakeup events must work at all times
>> which means that low power states can only safely be entered from idle.
>
> It's not clear what you mean by "some wakeup events must work at all times"
> and what "safely" means.
>
>> Suspend, in its current form, cannot be used, since wakeup events that
>> occur right after initiating suspend will not be processed until another
>> possibly unrelated event wake up the system again.
>
> Well, I _guess_ I know what you're trying to say, but I'm not sure if that's
> the core of the problem the patchset is supposed to address.
>
> The problem, as I see it, is really two-fold.
>
> First, to save as much energy as reasonably possible you need to put everything
> except for memory (ie. I/O devices and CPUs) into low-power states and let that
> stay in these low-power states for as long as reasonably possible, right?

Memory should also be in a low power state, but yes, everything should
be in the lowest power possible state for as long as possible.

>
> Second, you need the system to _always_ respond to some _specific_ events
> regardless of its current state, correct?
>
> Now, at present, we can put I/O devices and the CPU into low-power states
> at the same time in two ways: (1) by using runtime PM and cpuidle and (2) by
> suspending the system.  Unfortunately, none of these approaches is ideal,
> because (1) is vulnerable to periodic timers and polling apps (and CPU-bound
> apps) and (2) doesn't guarantee that all events you care about will be
> responded to.
>
> The proposed solution is to use suspend with an additional mechanism that
> will prevent the events that have to be responded to from being lost.  This
> additional mechanism is suspend blockers.
>
> Is this correct?

Yes.

>
>> >> > So, there is a difference and the explanation can go like this: "... to achieve
>> >> > maximum energy savings one has to put all I/O devices and the CPU into
>> >> > low-power states, but the CPU can only be put into a low-power state from
>> >> > idle.  This, in turn, means that the CPU leaves the low-power state on
>> >> > interrupts triggered by periodic timers and user space processes that use
>> >> > polling.  It turns out, however, that many of these events causing the CPU to
>> >> > leave the low-power state aren't essential for the desired system functionality
>> >> > and from the power management point of view it would be better if they didn't
>> >> > occur".
>> >>
>> >> This only explain why we still want to use suspend on systems that can
>> >> enter the same power states from idle and suspend.
>> >
>> > Sorry, I'm confused now.  Isn't that why you do that on Android?
>> >
>>
>> Yes, but it is not the only reason to use opportunistic support. It is
>> way more important to have opportunistic suspend support if the
>> hardware can enter lower power states from suspend than idle.
>
> Sure, but you can add something like "There also are systems where some
> devices cannot be put into low-power states without suspending the entire
> system (or the low-power states available to them without suspending the
> entire system are substantially shallower than the low-power states they are
> put into when the entire system is suspended), so the system have to be
> suspended as a whole to achieve the maximum energy savings".
>

Does this work for you:

PM: Opportunistic suspend support.

Power management features present in the current mainline kernel are
insufficient to get maximum possible energy savings on some platforms,
such as Android, because the system must always respond to certain
events. Suspend, in its current form, cannot be used on these
platforms, since wakeup events (events that wake the CPU from idle and
the system from suspend) that occur right after initiating suspend
will not be processed until another possibly unrelated event wake up
the system again.

On hardware where idle can enter the same power state as suspend, idle
combined with runtime PM can be used, but periodic wakeups increase
the average power consumption. Suspending the system also reduces the
harm caused by apps that never go idle. There also are systems where
some devices cannot be put into low-power states without suspending
the entire system (or the low-power states available to them without
suspending the entire system are substantially shallower than the
low-power states they are put into when the entire system is
suspended), so the system have to be suspended as a whole to achieve
the maximum energy savings.

To allow Android and similar platforms to save more energy than they
currently can save using the mainline kernel, introduce a mechanism by
which the system is automatically suspended (i.e. put into a
system-wide sleep state) whenever it's not doing useful work, called
opportunistic suspend.

For this purpose introduce the suspend blockers framework allowing the
kernel's power management subsystem to decide when it is desirable to
suspend the system (i.e. when the system is not doing anything the
user really cares about at the moment and therefore it may be
suspended). Add an API that that drivers can use to block
opportunistic suspend. This is needed to avoid losing wakeup events
that occur right after suspend is initiated.

Adds /sys/power/policy that selects the behavior of /sys/power/state.
After setting the policy to opportunistic, writes to /sys/power/state
become non-blocking requests that specify which suspend state to enter
when no suspend blockers are active. A special state, "on", stops the
process by activating the "main" suspend blocker.


-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18 16:18         ` Kevin Hilman
  2010-05-18 18:52           ` Rafael J. Wysocki
@ 2010-05-19  0:00           ` Arve Hjønnevåg
  1 sibling, 0 replies; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-19  0:00 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Rafael J. Wysocki, linux-pm, linux-kernel, Greg KH, Mark Brown,
	Alan Stern, Brian Swetland, Daniel Walker, Theodore Ts'o,
	Matthew Garrett

2010/5/18 Kevin Hilman <khilman@deeprootsystems.com>:
> Arve Hjønnevåg <arve@android.com> writes:
>
>>
>> PM: Opportunistic suspend support.
>>
>> Power management features present in the current mainline kernel are
>> insufficient to get maximum possible energy savings on some platforms,
>> such as Android, because low power states can only safely be entered
>> from idle.  Suspend, in its current form, cannot be used, since wakeup
>> events that occur right after initiating suspend will not be processed
>> until another possibly unrelated event wake up the system again.
>
> I think the problems with wakeups in the current suspend path need to
> be described in more detail.  In particular, why check_wakeup_irqs()
> is not enough etc.
>

check_wakeup_irqs only handles interrupts that occurred after the
interrupt was masked during suspend. If the interrupt occurred before
it was masked, it will not be pending when check_wakeup_irqs is
called.

>> On some systems idle combined with runtime PM can enter the same power
>> state as suspend, but periodic wakeups increase the average power
>> consumption. Suspending the system also reduces the harm caused by
>> apps that never go idle. On other systems suspend can enter a much
>> lower power state than idle.
>>
>> To allow Android and similar platforms to save more energy than they
>> currently can save using the mainline kernel, we introduce a mechanism
>> by which the system is automatically suspended (i.e. put into a
>> system-wide sleep state) whenever it's not doing useful work, called
>> opportunistic suspend.
>
> A definition of "useful work" here would provide clarity and would
> also help clarify by what criteria other on-going work is determined
> to be not useful.
>
> Kevin
>



-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18 23:42                       ` Arve Hjønnevåg
@ 2010-05-19 20:39                         ` Rafael J. Wysocki
  2010-05-19 21:34                           ` Arve Hjønnevåg
  0 siblings, 1 reply; 53+ messages in thread
From: Rafael J. Wysocki @ 2010-05-19 20:39 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: linux-pm, linux-kernel, Greg KH, Mark Brown, Kevin Hilman,
	Alan Stern, Brian Swetland, Daniel Walker, Theodore Ts'o,
	Matthew Garrett

On Wednesday 19 May 2010, Arve Hjønnevåg wrote:
> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Wednesday 19 May 2010, Arve Hjønnevåg wrote:
> >> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> >> > On Wednesday 19 May 2010, Arve Hjønnevåg wrote:
> >> >> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> >> >> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
> >> >> >> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> >> >> >> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
> >> >> >> >> 2010/5/17 Rafael J. Wysocki <rjw@sisk.pl>:
> >> >> >> >> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
> >> >> >> >> >> 2010/5/14 Rafael J. Wysocki <rjw@sisk.pl>:
> >> >> >> >> >> > On Friday 14 May 2010, Arve Hjønnevåg wrote:
> >> >> >> >> >> >> This patch series adds a suspend-block api that provides the same
> >> >> >> >> >> >> functionality as the android wakelock api. This version has some
> >> >> >> >> >> >> changes from, or requested by, Rafael. The most notable changes are:
> >> >> >> >> >> >> - DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
> >> >> >> >> >> >>   for statically allocated suspend blockers.
> >> >> >> >> >> >> - suspend_blocker_destroy is now called suspend_blocker_unregister
> >> >> >> >> >> >> - The user space mandatory _INIT ioctl has been replaced with an
> >> >> >> >> >> >>   optional _SET_NAME ioctl.
> >> >> >> >> >> >>
> >> >> >> >> >> >> I kept the ack and reviewed by tags on two of the patches even though
> >> >> >> >> >> >> there were a few cosmetic changes.
> >> >> >> >> >> >
> >> >> >> >> >> > Thanks for the patches, I think they are in a pretty good shape now.
> >> >> >> >> >> >
> >> >> >> >> >> > That said, I'd like the changelogs to be a bit more descriptive, at least for
> >> >> >> >> >> > patch [1/8].  I think it should explain (in a few words) what the purpose of
> >> >> >> >> >> > the feature is and what problems it solves that generally a combination of
> >> >> >> >> >> > runtime PM and cpuidle is not suitable for in your opinion.  IOW, why you
> >> >> >> >> >> > think we need that feature.
> >> >> >> >> >> >
> >> >> >> >> >>
> >> >> >> >> >> How about:
> >> >> >> >> >>
> >> >> >> >> >> PM: Add opportunistic suspend support.
> >> >> >> >> >
> >> >> >> >> > "PM: Opportunistic suspend support" would be sufficient IMO.
> >> >> >> >> >
> >> >> >> >> > Now, I'd start with the motivation.  Like "Power management features present
> >> >> >> >> > in the current mainline kernel are insufficient to get maximum possible energy
> >> >> >> >> > savings on some platforms, such as Android, because ..." (here go explanations
> >> >> >> >> > why this is the case in your opinion).
> >> >> >> >> >
> >> >> >> >> > Next, "To allow Android and similar platforms to save more energy than they
> >> >> >> >> > currently can save using the mainline kernel, introduce a mechanism by which
> >> >> >> >> > the system is automatically suspended (i.e. put into a system-wide sleep state)
> >> >> >> >> > whenever it's not doing useful work, called opportunistic suspend".
> >> >> >> >> >
> >> >> >> >> > "For this purpose introduce the suspend blockers framework allowing the
> >> >> >> >> > kernel's power management subsystem to decide when it is desirable to suspend
> >> >> >> >> > the system (i.e. when useful work is not being done).  Add an API that ..."
> >> >> >> >> >
> >> >> >> >>
> >> >> >> >> PM: Opportunistic suspend support.
> >> >> >> >>
> >> >> >> >> Power management features present in the current mainline kernel are
> >> >> >> >> insufficient to get maximum possible energy savings on some platforms,
> >> >> >> >> such as Android, because low power states can only safely be entered
> >> >> >> >> from idle.
> >> >> >> >
> >> >> >> > Do you mean CPU low-power states or system low-power states here?
> >> >> >> >
> >> >> >> I think either.
> >> >> >
> >> >> > The statement is not true for system low-power states (or sleep states),
> >> >> > because generally (ie. on many platforms) they aren't entered from idle.
> >> >> > Suspend is for entering them.
> >> >> >
> >> >> I don't think that makes my statement false. If you can only safely
> >> >> enter low power states from idle, but some low power states cannot be
> >> >> entered from idle, then it follows that you cannot safely enter those
> >> >> low power states.
> >> >
> >> > Define "safely", then.
> >> >
> >> OK. Is this clearer:
> >
> > Not really.
> >
> >> Power management features present in the current mainline kernel are
> >> insufficient to get maximum possible energy savings on some platforms,
> >> such as Android, because some wakeup events must work at all times
> >> which means that low power states can only safely be entered from idle.
> >
> > It's not clear what you mean by "some wakeup events must work at all times"
> > and what "safely" means.
> >
> >> Suspend, in its current form, cannot be used, since wakeup events that
> >> occur right after initiating suspend will not be processed until another
> >> possibly unrelated event wake up the system again.
> >
> > Well, I _guess_ I know what you're trying to say, but I'm not sure if that's
> > the core of the problem the patchset is supposed to address.
> >
> > The problem, as I see it, is really two-fold.
> >
> > First, to save as much energy as reasonably possible you need to put everything
> > except for memory (ie. I/O devices and CPUs) into low-power states and let that
> > stay in these low-power states for as long as reasonably possible, right?
> 
> Memory should also be in a low power state, but yes, everything should
> be in the lowest power possible state for as long as possible.
> 
> >
> > Second, you need the system to _always_ respond to some _specific_ events
> > regardless of its current state, correct?
> >
> > Now, at present, we can put I/O devices and the CPU into low-power states
> > at the same time in two ways: (1) by using runtime PM and cpuidle and (2) by
> > suspending the system.  Unfortunately, none of these approaches is ideal,
> > because (1) is vulnerable to periodic timers and polling apps (and CPU-bound
> > apps) and (2) doesn't guarantee that all events you care about will be
> > responded to.
> >
> > The proposed solution is to use suspend with an additional mechanism that
> > will prevent the events that have to be responded to from being lost.  This
> > additional mechanism is suspend blockers.
> >
> > Is this correct?
> 
> Yes.
> 
> >
> >> >> > So, there is a difference and the explanation can go like this: "... to achieve
> >> >> > maximum energy savings one has to put all I/O devices and the CPU into
> >> >> > low-power states, but the CPU can only be put into a low-power state from
> >> >> > idle.  This, in turn, means that the CPU leaves the low-power state on
> >> >> > interrupts triggered by periodic timers and user space processes that use
> >> >> > polling.  It turns out, however, that many of these events causing the CPU to
> >> >> > leave the low-power state aren't essential for the desired system functionality
> >> >> > and from the power management point of view it would be better if they didn't
> >> >> > occur".
> >> >>
> >> >> This only explain why we still want to use suspend on systems that can
> >> >> enter the same power states from idle and suspend.
> >> >
> >> > Sorry, I'm confused now.  Isn't that why you do that on Android?
> >> >
> >>
> >> Yes, but it is not the only reason to use opportunistic support. It is
> >> way more important to have opportunistic suspend support if the
> >> hardware can enter lower power states from suspend than idle.
> >
> > Sure, but you can add something like "There also are systems where some
> > devices cannot be put into low-power states without suspending the entire
> > system (or the low-power states available to them without suspending the
> > entire system are substantially shallower than the low-power states they are
> > put into when the entire system is suspended), so the system have to be
> > suspended as a whole to achieve the maximum energy savings".
> >
> 
> Does this work for you:

Well, almost.

> PM: Opportunistic suspend support.
> 
> Power management features present in the current mainline kernel are
> insufficient to get maximum possible energy savings on some platforms,
> such as Android,

I'd finish the first sentence here.

> because the system must always respond to certain
> events. Suspend, in its current form, cannot be used on these
> platforms,

This doesn't seem to be correct.  Surely you can suspend these systems, but
you can't address the problem at hand using suspend as is.

I'd say (in the second sentence) "The problem is that to save maximum amount of
energy all system hardware components need to be in the lowest-power states
available for as long as reasonably possible, but at the same time the system
must always respond to certain events, regardless of the current state of the
hardware.

The first goal can be achieved either by using device runtime PM and cpuidle to
put all hardware into low-power states, transparently from the user space point
of view, or by suspending the whole system.  However, system suspend, in its
current form, does not guarantee that the events of interest will always be
responded to, since wakeup events ..."

> since wakeup events (events that wake the CPU from idle and
> the system from suspend) that occur right after initiating suspend
> will not be processed until another possibly unrelated event wake up

"... wakes up ..." I guess.

> the system again.
> 
> On hardware where idle can enter the same power state as suspend, idle
> combined with runtime PM can be used, but periodic wakeups increase
> the average power consumption. Suspending the system also reduces the
> harm caused by apps that never go idle. There also are systems where
> some devices cannot be put into low-power states without suspending
> the entire system (or the low-power states available to them without
> suspending the entire system are substantially shallower than the
> low-power states they are put into when the entire system is
> suspended), so the system have to be suspended as a whole to achieve
> the maximum energy savings.
> 
> To allow Android and similar platforms to save more energy than they
> currently can save using the mainline kernel, introduce a mechanism by
> which the system is automatically suspended (i.e. put into a
> system-wide sleep state) whenever it's not doing useful work, called
> opportunistic suspend.

I'd say "... whenever it's not doing work that's immediately useful to the
user, called  ..." or something like this.

The rest is fine by me.

Rafael

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-18 23:06                       ` Arve Hjønnevåg
@ 2010-05-19 20:40                         ` Rafael J. Wysocki
  0 siblings, 0 replies; 53+ messages in thread
From: Rafael J. Wysocki @ 2010-05-19 20:40 UTC (permalink / raw)
  To: Arve Hjønnevåg; +Cc: Brian Swetland, linux-pm, linux-kernel

On Wednesday 19 May 2010, Arve Hjønnevåg wrote:
> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Wednesday 19 May 2010, Arve Hjønnevåg wrote:
> >> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> >> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
> >> >> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
> >> >> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
> >> >> >> On Mon, May 17, 2010 at 2:44 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> >> >> >> > On Monday 17 May 2010, Brian Swetland wrote:
> >> >> >> >> On Mon, May 17, 2010 at 1:40 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> >> >> >> >> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
> >> >> >> >> >>
> >> > ...
> >> >>
> >> >> > Now, to make it more "user-friendly", we can simply use
> >> >> > queue_delayed_work() with a reasonable delay instead of queue_work() to queue
> >> >> > the suspend work (the delay may be configurable via sysfs).
> >> >> >
> >> >>
> >> >> I can add a delay (and the timeout support code does add a delay as an
> >> >> optimization) to the unknown wakeup case, but this does not fix the
> >> >> problem of a user turning on opportunistic suspend with a user space
> >> >> framework that does not use suspend blockers. If the kernel uses
> >> >> suspend blockers to make sure the wakeup event makes it to user space,
> >> >> but user space does not block suspend, then the system will suspend
> >> >> before the event is processed.
> >> >
> >> > But the user can still manually write to /sys/power/state. :-)
> >> >
> >>
> >> Does adding or removing a delay change this? It seems in only changes
> >> how quickly the user can finish that write.
> >
> > Yes, but that should allow the user to avoid rebooting the system if he does
> > the "wrong thing".
> >
> >> I'm not convinced adding a configurable delay here is necessary.
> >
> > No, it's not, but it would be useful in some cases IMO.  Pretty much the same
> > way your debug features are useful.
> >
> >> Once the driver that enabled the wakeup event has been updated to block
> >> suspend until this event gets to user space, then this delay will
> >> never be triggered. The kernel cannot tell the difference between a
> >> user enabling opportunistic suspend but not wanting it and
> >> opportunistic suspend aware user space code deciding that this wakeup
> >> event should be ignored.
> >
> > The point is, if there's a delay, it may be too aggressive for some users and
> > too conservative for some other users, so it makes sense to provide a means
> > to adjust it to the user's needs.
> >
> 
> My point is that the delay will not be used at all if the driver uses
> a suspend blocker (like it should). Why add a configuration option for
> opportunistic suspend that only works when the driver does not support
> opportunistic suspend.

Because on many systems there are no such drivers (yet, at least).

Rafael

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-19 20:39                         ` Rafael J. Wysocki
@ 2010-05-19 21:34                           ` Arve Hjønnevåg
  2010-05-20 22:21                             ` Rafael J. Wysocki
  0 siblings, 1 reply; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-19 21:34 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-pm, linux-kernel, Greg KH, Mark Brown, Kevin Hilman,
	Alan Stern, Brian Swetland, Daniel Walker, Theodore Ts'o,
	Matthew Garrett

2010/5/19 Rafael J. Wysocki <rjw@sisk.pl>:
> On Wednesday 19 May 2010, Arve Hjønnevåg wrote:
>> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
>> > On Wednesday 19 May 2010, Arve Hjønnevåg wrote:
>> >> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
>> >> > On Wednesday 19 May 2010, Arve Hjønnevåg wrote:
>> >> >> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
>> >> >> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
>> >> >> >> 2010/5/18 Rafael J. Wysocki <rjw@sisk.pl>:
>> >> >> >> > On Tuesday 18 May 2010, Arve Hjønnevåg wrote:
>> >> >> >> >> 2010/5/17 Rafael J. Wysocki <rjw@sisk.pl>:
>> >> >> >> >> > On Monday 17 May 2010, Arve Hjønnevåg wrote:
>> >> >> >> >> >> 2010/5/14 Rafael J. Wysocki <rjw@sisk.pl>:
>> >> >> >> >> >> > On Friday 14 May 2010, Arve Hjønnevåg wrote:
>> >> >> >> >> >> >> This patch series adds a suspend-block api that provides the same
>> >> >> >> >> >> >> functionality as the android wakelock api. This version has some
>> >> >> >> >> >> >> changes from, or requested by, Rafael. The most notable changes are:
>> >> >> >> >> >> >> - DEFINE_SUSPEND_BLOCKER and suspend_blocker_register have been added
>> >> >> >> >> >> >>   for statically allocated suspend blockers.
>> >> >> >> >> >> >> - suspend_blocker_destroy is now called suspend_blocker_unregister
>> >> >> >> >> >> >> - The user space mandatory _INIT ioctl has been replaced with an
>> >> >> >> >> >> >>   optional _SET_NAME ioctl.
>> >> >> >> >> >> >>
>> >> >> >> >> >> >> I kept the ack and reviewed by tags on two of the patches even though
>> >> >> >> >> >> >> there were a few cosmetic changes.
>> >> >> >> >> >> >
>> >> >> >> >> >> > Thanks for the patches, I think they are in a pretty good shape now.
>> >> >> >> >> >> >
>> >> >> >> >> >> > That said, I'd like the changelogs to be a bit more descriptive, at least for
>> >> >> >> >> >> > patch [1/8].  I think it should explain (in a few words) what the purpose of
>> >> >> >> >> >> > the feature is and what problems it solves that generally a combination of
>> >> >> >> >> >> > runtime PM and cpuidle is not suitable for in your opinion.  IOW, why you
>> >> >> >> >> >> > think we need that feature.
>> >> >> >> >> >> >
>> >> >> >> >> >>
>> >> >> >> >> >> How about:
>> >> >> >> >> >>
>> >> >> >> >> >> PM: Add opportunistic suspend support.
>> >> >> >> >> >
>> >> >> >> >> > "PM: Opportunistic suspend support" would be sufficient IMO.
>> >> >> >> >> >
>> >> >> >> >> > Now, I'd start with the motivation.  Like "Power management features present
>> >> >> >> >> > in the current mainline kernel are insufficient to get maximum possible energy
>> >> >> >> >> > savings on some platforms, such as Android, because ..." (here go explanations
>> >> >> >> >> > why this is the case in your opinion).
>> >> >> >> >> >
>> >> >> >> >> > Next, "To allow Android and similar platforms to save more energy than they
>> >> >> >> >> > currently can save using the mainline kernel, introduce a mechanism by which
>> >> >> >> >> > the system is automatically suspended (i.e. put into a system-wide sleep state)
>> >> >> >> >> > whenever it's not doing useful work, called opportunistic suspend".
>> >> >> >> >> >
>> >> >> >> >> > "For this purpose introduce the suspend blockers framework allowing the
>> >> >> >> >> > kernel's power management subsystem to decide when it is desirable to suspend
>> >> >> >> >> > the system (i.e. when useful work is not being done).  Add an API that ..."
>> >> >> >> >> >
>> >> >> >> >>
>> >> >> >> >> PM: Opportunistic suspend support.
>> >> >> >> >>
>> >> >> >> >> Power management features present in the current mainline kernel are
>> >> >> >> >> insufficient to get maximum possible energy savings on some platforms,
>> >> >> >> >> such as Android, because low power states can only safely be entered
>> >> >> >> >> from idle.
>> >> >> >> >
>> >> >> >> > Do you mean CPU low-power states or system low-power states here?
>> >> >> >> >
>> >> >> >> I think either.
>> >> >> >
>> >> >> > The statement is not true for system low-power states (or sleep states),
>> >> >> > because generally (ie. on many platforms) they aren't entered from idle.
>> >> >> > Suspend is for entering them.
>> >> >> >
>> >> >> I don't think that makes my statement false. If you can only safely
>> >> >> enter low power states from idle, but some low power states cannot be
>> >> >> entered from idle, then it follows that you cannot safely enter those
>> >> >> low power states.
>> >> >
>> >> > Define "safely", then.
>> >> >
>> >> OK. Is this clearer:
>> >
>> > Not really.
>> >
>> >> Power management features present in the current mainline kernel are
>> >> insufficient to get maximum possible energy savings on some platforms,
>> >> such as Android, because some wakeup events must work at all times
>> >> which means that low power states can only safely be entered from idle.
>> >
>> > It's not clear what you mean by "some wakeup events must work at all times"
>> > and what "safely" means.
>> >
>> >> Suspend, in its current form, cannot be used, since wakeup events that
>> >> occur right after initiating suspend will not be processed until another
>> >> possibly unrelated event wake up the system again.
>> >
>> > Well, I _guess_ I know what you're trying to say, but I'm not sure if that's
>> > the core of the problem the patchset is supposed to address.
>> >
>> > The problem, as I see it, is really two-fold.
>> >
>> > First, to save as much energy as reasonably possible you need to put everything
>> > except for memory (ie. I/O devices and CPUs) into low-power states and let that
>> > stay in these low-power states for as long as reasonably possible, right?
>>
>> Memory should also be in a low power state, but yes, everything should
>> be in the lowest power possible state for as long as possible.
>>
>> >
>> > Second, you need the system to _always_ respond to some _specific_ events
>> > regardless of its current state, correct?
>> >
>> > Now, at present, we can put I/O devices and the CPU into low-power states
>> > at the same time in two ways: (1) by using runtime PM and cpuidle and (2) by
>> > suspending the system.  Unfortunately, none of these approaches is ideal,
>> > because (1) is vulnerable to periodic timers and polling apps (and CPU-bound
>> > apps) and (2) doesn't guarantee that all events you care about will be
>> > responded to.
>> >
>> > The proposed solution is to use suspend with an additional mechanism that
>> > will prevent the events that have to be responded to from being lost.  This
>> > additional mechanism is suspend blockers.
>> >
>> > Is this correct?
>>
>> Yes.
>>
>> >
>> >> >> > So, there is a difference and the explanation can go like this: "... to achieve
>> >> >> > maximum energy savings one has to put all I/O devices and the CPU into
>> >> >> > low-power states, but the CPU can only be put into a low-power state from
>> >> >> > idle.  This, in turn, means that the CPU leaves the low-power state on
>> >> >> > interrupts triggered by periodic timers and user space processes that use
>> >> >> > polling.  It turns out, however, that many of these events causing the CPU to
>> >> >> > leave the low-power state aren't essential for the desired system functionality
>> >> >> > and from the power management point of view it would be better if they didn't
>> >> >> > occur".
>> >> >>
>> >> >> This only explain why we still want to use suspend on systems that can
>> >> >> enter the same power states from idle and suspend.
>> >> >
>> >> > Sorry, I'm confused now.  Isn't that why you do that on Android?
>> >> >
>> >>
>> >> Yes, but it is not the only reason to use opportunistic support. It is
>> >> way more important to have opportunistic suspend support if the
>> >> hardware can enter lower power states from suspend than idle.
>> >
>> > Sure, but you can add something like "There also are systems where some
>> > devices cannot be put into low-power states without suspending the entire
>> > system (or the low-power states available to them without suspending the
>> > entire system are substantially shallower than the low-power states they are
>> > put into when the entire system is suspended), so the system have to be
>> > suspended as a whole to achieve the maximum energy savings".
>> >
>>
>> Does this work for you:
>
> Well, almost.
>
>> PM: Opportunistic suspend support.
>>
>> Power management features present in the current mainline kernel are
>> insufficient to get maximum possible energy savings on some platforms,
>> such as Android,
>
> I'd finish the first sentence here.
>
>> because the system must always respond to certain
>> events. Suspend, in its current form, cannot be used on these
>> platforms,
>
> This doesn't seem to be correct.  Surely you can suspend these systems, but
> you can't address the problem at hand using suspend as is.
>
> I'd say (in the second sentence) "The problem is that to save maximum amount of
> energy all system hardware components need to be in the lowest-power states
> available for as long as reasonably possible, but at the same time the system
> must always respond to certain events, regardless of the current state of the
> hardware.
>
> The first goal can be achieved either by using device runtime PM and cpuidle to
> put all hardware into low-power states, transparently from the user space point
> of view, or by suspending the whole system.  However, system suspend, in its
> current form, does not guarantee that the events of interest will always be
> responded to, since wakeup events ..."
>
>> since wakeup events (events that wake the CPU from idle and
>> the system from suspend) that occur right after initiating suspend
>> will not be processed until another possibly unrelated event wake up
>
> "... wakes up ..." I guess.
>
>> the system again.
>>
>> On hardware where idle can enter the same power state as suspend, idle
>> combined with runtime PM can be used, but periodic wakeups increase
>> the average power consumption. Suspending the system also reduces the
>> harm caused by apps that never go idle. There also are systems where
>> some devices cannot be put into low-power states without suspending
>> the entire system (or the low-power states available to them without
>> suspending the entire system are substantially shallower than the
>> low-power states they are put into when the entire system is
>> suspended), so the system have to be suspended as a whole to achieve
>> the maximum energy savings.
>>
>> To allow Android and similar platforms to save more energy than they
>> currently can save using the mainline kernel, introduce a mechanism by
>> which the system is automatically suspended (i.e. put into a
>> system-wide sleep state) whenever it's not doing useful work, called
>> opportunistic suspend.
>
> I'd say "... whenever it's not doing work that's immediately useful to the
> user, called  ..." or something like this.
>
> The rest is fine by me.
>

PM: Opportunistic suspend support.

Power management features present in the current mainline kernel are
insufficient to get maximum possible energy savings on some platforms,
such as Android.  The problem is that to save maximum amount of energy
all system hardware components need to be in the lowest-power states
available for as long as reasonably possible, but at the same time the
system must always respond to certain events, regardless of the
current state of the hardware.

The first goal can be achieved either by using device runtime PM and
cpuidle to put all hardware into low-power states, transparently from
the user space point of view, or by suspending the whole system.
However, system suspend, in its current form, does not guarantee that
the events of interest will always be responded to, since wakeup
events (events that wake the CPU from idle and the system from
suspend) that occur right after initiating suspend will not be
processed until another possibly unrelated event wakes the system up
again.

On hardware where idle can enter the same power state as suspend, idle
combined with runtime PM can be used, but periodic wakeups increase
the average power consumption. Suspending the system also reduces the
harm caused by apps that never go idle. There also are systems where
some devices cannot be put into low-power states without suspending
the entire system (or the low-power states available to them without
suspending the entire system are substantially shallower than the
low-power states they are put into when the entire system is
suspended), so the system has to be suspended as a whole to achieve
the maximum energy savings.

To allow Android and similar platforms to save more energy than they
currently can save using the mainline kernel, introduce a mechanism by
which the system is automatically suspended (i.e. put into a
system-wide sleep state) whenever it's not doing work that's
immediately useful to the user, called opportunistic suspend.

For this purpose introduce the suspend blockers framework allowing the
kernel's power management subsystem to decide when it is desirable to
suspend the system (i.e. when the system is not doing anything the
user really cares about at the moment and therefore it may be
suspended). Add an API that that drivers can use to block
opportunistic suspend. This is needed to avoid losing wakeup events
that occur right after suspend is initiated.

Add /sys/power/policy that selects the behavior of /sys/power/state.
After setting the policy to opportunistic, writes to /sys/power/state
become non-blocking requests that specify which suspend state to enter
when no suspend blockers are active. A special state, "on", stops the
process by activating the "main" suspend blocker.

-- 
Arve Hjønnevåg

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2010-05-18 13:11   ` [PATCH 1/8] PM: Add suspend block api Pavel Machek
@ 2010-05-20  9:11     ` Florian Mickler
  2010-05-20  9:26       ` Florian Mickler
  0 siblings, 1 reply; 53+ messages in thread
From: Florian Mickler @ 2010-05-20  9:11 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Arve Hj??nnev??g, linux-pm, linux-kernel, Rafael J. Wysocki,
	Len Brown, Randy Dunlap, Andrew Morton, Andi Kleen,
	Cornelia Huck, Tejun Heo, Jesse Barnes, Magnus Damm,
	Nigel Cunningham, Alan Stern, Ming Lei, Wu Fengguang,
	Maxim Levitsky, linux-doc

On Tue, 18 May 2010 15:11:11 +0200
Pavel Machek <pavel@ucw.cz> wrote:

> On Thu 2010-05-13 21:11:06, Arve Hj??nnev??g wrote:
> > Adds /sys/power/policy that selects the behaviour of /sys/power/state.
> > After setting the policy to opportunistic, writes to /sys/power/state
> > become non-blocking requests that specify which suspend state to
> > enter
> 
> Yeah, one file selects behavior of another file, and to read available
> states for opportunistic, you have to write to file first.
> 
> I still don't like the interface.
> 

Actually, what would be a better interface? 

I wonder why it is not like this:

/sys/power/state 
	no change, works with and without opportunistic suspend the
	same. Ignores suspend blockers. Really no change. (From user
	perspective)

/sys/power/opportunistic
	On / Off
	While Off the opportunistic suspend is off.
	While On, the opportunistic suspend is on and if there are no
	suspend blockers the system goes to suspend. 

Cheers,
Flo




^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2010-05-20  9:11     ` Florian Mickler
@ 2010-05-20  9:26       ` Florian Mickler
  2010-05-20 22:18         ` Rafael J. Wysocki
  0 siblings, 1 reply; 53+ messages in thread
From: Florian Mickler @ 2010-05-20  9:26 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Arve Hj??nnev??g, linux-pm, linux-kernel, Rafael J. Wysocki,
	Len Brown, Randy Dunlap, Andrew Morton, Andi Kleen,
	Cornelia Huck, Tejun Heo, Jesse Barnes, Magnus Damm,
	Nigel Cunningham, Alan Stern, Ming Lei, Wu Fengguang,
	Maxim Levitsky, linux-doc

On Thu, 20 May 2010 11:11:11 +0200
Florian Mickler <florian@mickler.org> wrote:

> On Tue, 18 May 2010 15:11:11 +0200
> Pavel Machek <pavel@ucw.cz> wrote:
> 
> > On Thu 2010-05-13 21:11:06, Arve Hj??nnev??g wrote:
> > > Adds /sys/power/policy that selects the behaviour of /sys/power/state.
> > > After setting the policy to opportunistic, writes to /sys/power/state
> > > become non-blocking requests that specify which suspend state to
> > > enter
> > 
> > Yeah, one file selects behavior of another file, and to read available
> > states for opportunistic, you have to write to file first.
> > 
> > I still don't like the interface.
> > 
> 
> Actually, what would be a better interface? 
> 
> I wonder why it is not like this:
> 
> /sys/power/state 
> 	no change, works with and without opportunistic suspend the
> 	same. Ignores suspend blockers. Really no change. (From user
> 	perspective)
> 
> /sys/power/opportunistic
> 	On / Off
> 	While Off the opportunistic suspend is off.
> 	While On, the opportunistic suspend is on and if there are no
> 	suspend blockers the system goes to suspend. 
> 

I forgot, of course there needs to be another knob to implement the
"on" behaviour  in the opportunistic mode

 /sys/power/block_opportunistic_suspend

There you have it. One file, one purpose. 

> Cheers,
> Flo

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2010-05-20  9:26       ` Florian Mickler
@ 2010-05-20 22:18         ` Rafael J. Wysocki
  2010-05-21  6:04           ` Florian Mickler
  2010-05-27 15:41           ` Pavel Machek
  0 siblings, 2 replies; 53+ messages in thread
From: Rafael J. Wysocki @ 2010-05-20 22:18 UTC (permalink / raw)
  To: Florian Mickler
  Cc: Pavel Machek, Arve Hj??nnev??g, linux-pm, linux-kernel,
	Len Brown, Randy Dunlap, Andrew Morton, Andi Kleen,
	Cornelia Huck, Tejun Heo, Jesse Barnes, Magnus Damm,
	Nigel Cunningham, Alan Stern, Ming Lei, Wu Fengguang,
	Maxim Levitsky, linux-doc

On Thursday 20 May 2010, Florian Mickler wrote:
> On Thu, 20 May 2010 11:11:11 +0200
> Florian Mickler <florian@mickler.org> wrote:
> 
> > On Tue, 18 May 2010 15:11:11 +0200
> > Pavel Machek <pavel@ucw.cz> wrote:
> > 
> > > On Thu 2010-05-13 21:11:06, Arve Hj??nnev??g wrote:
> > > > Adds /sys/power/policy that selects the behaviour of /sys/power/state.
> > > > After setting the policy to opportunistic, writes to /sys/power/state
> > > > become non-blocking requests that specify which suspend state to
> > > > enter
> > > 
> > > Yeah, one file selects behavior of another file, and to read available
> > > states for opportunistic, you have to write to file first.
> > > 
> > > I still don't like the interface.
> > > 
> > 
> > Actually, what would be a better interface? 
> > 
> > I wonder why it is not like this:

Because I think the "forced" and "opportunistic" suspend "modes" are mutually
exclusive in practice and the interface as proposed reflects that quite well.

> > /sys/power/state 
> > 	no change, works with and without opportunistic suspend the
> > 	same. Ignores suspend blockers. Really no change. (From user
> > 	perspective)
> > 
> > /sys/power/opportunistic
> > 	On / Off
> > 	While Off the opportunistic suspend is off.
> > 	While On, the opportunistic suspend is on and if there are no
> > 	suspend blockers the system goes to suspend. 
> > 
> 
> I forgot, of course there needs to be another knob to implement the
> "on" behaviour  in the opportunistic mode
> 
>  /sys/power/block_opportunistic_suspend
> 
> There you have it. One file, one purpose. 

That's getting messy IMHO.

In addition to that you get a nice race when the user writes "mem"
to /sys/power/state and opportunistic suspend happens at the same time.
If the latter wins the race, the system will suspend again immediately after
being woken up, which probably is not the result you'd like to get.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 0/8] Suspend block api (version 7)
  2010-05-19 21:34                           ` Arve Hjønnevåg
@ 2010-05-20 22:21                             ` Rafael J. Wysocki
  0 siblings, 0 replies; 53+ messages in thread
From: Rafael J. Wysocki @ 2010-05-20 22:21 UTC (permalink / raw)
  To: Arve Hjønnevåg
  Cc: linux-pm, linux-kernel, Greg KH, Mark Brown, Kevin Hilman,
	Alan Stern, Brian Swetland, Daniel Walker, Theodore Ts'o,
	Matthew Garrett

On Wednesday 19 May 2010, Arve Hjønnevåg wrote:
...
> PM: Opportunistic suspend support.
> 
> Power management features present in the current mainline kernel are
> insufficient to get maximum possible energy savings on some platforms,
> such as Android.  The problem is that to save maximum amount of energy
> all system hardware components need to be in the lowest-power states
> available for as long as reasonably possible, but at the same time the
> system must always respond to certain events, regardless of the
> current state of the hardware.
> 
> The first goal can be achieved either by using device runtime PM and
> cpuidle to put all hardware into low-power states, transparently from
> the user space point of view, or by suspending the whole system.
> However, system suspend, in its current form, does not guarantee that
> the events of interest will always be responded to, since wakeup
> events (events that wake the CPU from idle and the system from
> suspend) that occur right after initiating suspend will not be
> processed until another possibly unrelated event wakes the system up
> again.
> 
> On hardware where idle can enter the same power state as suspend, idle
> combined with runtime PM can be used, but periodic wakeups increase
> the average power consumption. Suspending the system also reduces the
> harm caused by apps that never go idle. There also are systems where
> some devices cannot be put into low-power states without suspending
> the entire system (or the low-power states available to them without
> suspending the entire system are substantially shallower than the
> low-power states they are put into when the entire system is
> suspended), so the system has to be suspended as a whole to achieve
> the maximum energy savings.
> 
> To allow Android and similar platforms to save more energy than they
> currently can save using the mainline kernel, introduce a mechanism by
> which the system is automatically suspended (i.e. put into a
> system-wide sleep state) whenever it's not doing work that's
> immediately useful to the user, called opportunistic suspend.
> 
> For this purpose introduce the suspend blockers framework allowing the
> kernel's power management subsystem to decide when it is desirable to
> suspend the system (i.e. when the system is not doing anything the
> user really cares about at the moment and therefore it may be
> suspended). Add an API that that drivers can use to block
> opportunistic suspend. This is needed to avoid losing wakeup events
> that occur right after suspend is initiated.
> 
> Add /sys/power/policy that selects the behavior of /sys/power/state.
> After setting the policy to opportunistic, writes to /sys/power/state
> become non-blocking requests that specify which suspend state to enter
> when no suspend blockers are active. A special state, "on", stops the
> process by activating the "main" suspend blocker.

That looks good to me.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2010-05-20 22:18         ` Rafael J. Wysocki
@ 2010-05-21  6:04           ` Florian Mickler
  2010-05-27 15:41           ` Pavel Machek
  1 sibling, 0 replies; 53+ messages in thread
From: Florian Mickler @ 2010-05-21  6:04 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Pavel Machek, Arve Hj??nnev??g, linux-pm, linux-kernel,
	Len Brown, Randy Dunlap, Andrew Morton, Andi Kleen,
	Cornelia Huck, Tejun Heo, Jesse Barnes, Magnus Damm,
	Nigel Cunningham, Alan Stern, Ming Lei, Wu Fengguang,
	Maxim Levitsky, linux-doc

On Fri, 21 May 2010 00:18:43 +0200
"Rafael J. Wysocki" <rjw@sisk.pl> wrote:

> > > Actually, what would be a better interface? 
> > > 
> > > I wonder why it is not like this:
> 
> Because I think the "forced" and "opportunistic" suspend "modes" are mutually
> exclusive in practice and the interface as proposed reflects that quite well.
> 
> > > /sys/power/state 
> > > 	no change, works with and without opportunistic suspend the
> > > 	same. Ignores suspend blockers. Really no change. (From user
> > > 	perspective)
> > > 
> > > /sys/power/opportunistic
> > > 	On / Off
> > > 	While Off the opportunistic suspend is off.
> > > 	While On, the opportunistic suspend is on and if there are no
> > > 	suspend blockers the system goes to suspend. 
> > > 
> > 
> > I forgot, of course there needs to be another knob to implement the
> > "on" behaviour  in the opportunistic mode
> > 
> >  /sys/power/block_opportunistic_suspend
> > 
> > There you have it. One file, one purpose. 
> 
> That's getting messy IMHO.
> 
> In addition to that you get a nice race when the user writes "mem"
> to /sys/power/state and opportunistic suspend happens at the same time.
> If the latter wins the race, the system will suspend again immediately after
> being woken up, which probably is not the result you'd like to get.

But I don't think there is a problem with that. If the system is
'awake' (suspend blocked) and you hit it with forced 'mem', the system
_has_ to suspend. as that is what forced "mem"  means. And if
opportunistic won the race you would _expect_ the machine to suspend
again after the wakeup (and this time for good).

But perhaps this only makes sense if you can specify different
wake-events for opportunistic and forced suspend.

This is probably some kind of bikeshed by now. I'm alright with the
status quo. For what it's worth (not much): You can add my Reviewed-By.

Cheers,
Flo


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 1/8] PM: Add suspend block api.
  2010-05-20 22:18         ` Rafael J. Wysocki
  2010-05-21  6:04           ` Florian Mickler
@ 2010-05-27 15:41           ` Pavel Machek
  1 sibling, 0 replies; 53+ messages in thread
From: Pavel Machek @ 2010-05-27 15:41 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Florian Mickler, Arve Hj??nnev??g, linux-pm, linux-kernel,
	Len Brown, Randy Dunlap, Andrew Morton, Andi Kleen,
	Cornelia Huck, Tejun Heo, Jesse Barnes, Magnus Damm,
	Nigel Cunningham, Alan Stern, Ming Lei, Wu Fengguang,
	Maxim Levitsky, linux-doc

Hi!

> > > > Yeah, one file selects behavior of another file, and to read available
> > > > states for opportunistic, you have to write to file first.
> > > > 
> > > > I still don't like the interface.
> > > > 
> > > 
> > > Actually, what would be a better interface? 
> > > 
> > > I wonder why it is not like this:
> 
> Because I think the "forced" and "opportunistic" suspend "modes" are mutually
> exclusive in practice and the interface as proposed reflects that quite well.

Why should they be? Forced disk while opportunistic mem is active
makes a lot of sense. If code can't support it now, just return
-EINVAL, but please don't cripple the interface just because of that.

> > > /sys/power/state 
> > > 	no change, works with and without opportunistic suspend the
> > > 	same. Ignores suspend blockers. Really no change. (From user
> > > 	perspective)
> > > 
> > > /sys/power/opportunistic
> > > 	On / Off
> > > 	While Off the opportunistic suspend is off.
> > > 	While On, the opportunistic suspend is on and if there are no
> > > 	suspend blockers the system goes to suspend. 
> > > 
> > 
> > I forgot, of course there needs to be another knob to implement the
> > "on" behaviour  in the opportunistic mode
> > 
> >  /sys/power/block_opportunistic_suspend
> > 
> > There you have it. One file, one purpose. 
> 
> That's getting messy IMHO.
> 
> In addition to that you get a nice race when the user writes "mem"
> to /sys/power/state and opportunistic suspend happens at the same
> time.

It should not opportunistically suspend when it has work to do (like
entering forced suspend).
									Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH 5/8] PM: suspend_block: Add suspend_blocker stats
  2010-05-21 22:46       ` [PATCH 4/8] PM: suspend_block: Add debugfs file Arve Hjønnevåg
@ 2010-05-21 22:46         ` Arve Hjønnevåg
  0 siblings, 0 replies; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-05-21 22:46 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Rafael J. Wysocki, Arve Hjønnevåg, Pavel Machek,
	Tejun Heo, Len Brown, Jesse Barnes, Magnus Damm, Wu Fengguang,
	Andrew Morton, Maxim Levitsky

Report suspend block stats in /sys/kernel/debug/suspend_blockers.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 include/linux/suspend_blocker.h      |   27 +++++-
 kernel/power/Kconfig                 |    8 ++
 kernel/power/opportunistic_suspend.c |  195 +++++++++++++++++++++++++++++++++-
 kernel/power/power.h                 |    5 +
 kernel/power/suspend.c               |    4 +-
 5 files changed, 235 insertions(+), 4 deletions(-)

diff --git a/include/linux/suspend_blocker.h b/include/linux/suspend_blocker.h
index 8788302..256af15 100755
--- a/include/linux/suspend_blocker.h
+++ b/include/linux/suspend_blocker.h
@@ -17,11 +17,35 @@
 #define _LINUX_SUSPEND_BLOCKER_H
 
 #include <linux/list.h>
+#include <linux/ktime.h>
+
+/**
+ * struct suspend_blocker_stats - statistics for a suspend blocker
+ *
+ * @count: Number of times this blocker has been deacivated.
+ * @wakeup_count: Number of times this blocker was the first to block suspend
+ *	after resume.
+ * @total_time: Total time this suspend blocker has prevented suspend.
+ * @prevent_suspend_time: Time this suspend blocker has prevented suspend while
+ *	user-space requested suspend.
+ * @max_time: Max time this suspend blocker has been continuously active.
+ * @last_time: Monotonic clock when the active state last changed.
+ */
+struct suspend_blocker_stats {
+#ifdef CONFIG_SUSPEND_BLOCKER_STATS
+	unsigned int count;
+	unsigned int wakeup_count;
+	ktime_t total_time;
+	ktime_t prevent_suspend_time;
+	ktime_t max_time;
+	ktime_t last_time;
+#endif
+};
 
 /**
  * struct suspend_blocker - the basic suspend_blocker structure
  * @link: List entry for active or inactive list.
- * @flags: Tracks initialized and active state.
+ * @flags: Tracks initialized and active state and statistics.
  * @name: Suspend blocker name used for debugging.
  *
  * When a suspend_blocker is active it prevents the system from entering
@@ -34,6 +58,7 @@ struct suspend_blocker {
 	struct list_head link;
 	int flags;
 	const char *name;
+	struct suspend_blocker_stats stat;
 #endif
 };
 
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 2e665cd..16a2570 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -146,6 +146,14 @@ config OPPORTUNISTIC_SUSPEND
 	  determines the sleep state the system will be put into when there are
 	  no active suspend blockers.
 
+config SUSPEND_BLOCKER_STATS
+	bool "Suspend blockers statistics"
+	depends on OPPORTUNISTIC_SUSPEND
+	default y
+	---help---
+	  Use /sys/kernel/debug/suspend_blockers to report suspend blockers
+	  statistics.
+
 config USER_SUSPEND_BLOCKERS
 	bool "User space suspend blockers"
 	depends on OPPORTUNISTIC_SUSPEND
diff --git a/kernel/power/opportunistic_suspend.c b/kernel/power/opportunistic_suspend.c
index 6b5eb1d..a8824ba 100644
--- a/kernel/power/opportunistic_suspend.c
+++ b/kernel/power/opportunistic_suspend.c
@@ -39,6 +39,7 @@ module_param_named(unknown_wakeup_delay_msecs, unknown_wakeup_delay_msecs, int,
 
 #define SB_INITIALIZED            (1U << 8)
 #define SB_ACTIVE                 (1U << 9)
+#define SB_PREVENTING_SUSPEND     (1U << 10)
 
 DEFINE_SUSPEND_BLOCKER(main_suspend_blocker, main);
 
@@ -51,6 +52,117 @@ static suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
 static bool enable_suspend_blockers;
 static DEFINE_SUSPEND_BLOCKER(unknown_wakeup, unknown_wakeups);
 
+#ifdef CONFIG_SUSPEND_BLOCKER_STATS
+static struct suspend_blocker_stats dropped_suspend_blockers;
+static ktime_t last_sleep_time_update;
+static bool wait_for_wakeup;
+
+static void suspend_blocker_stat_init(struct suspend_blocker_stats *stat)
+{
+	stat->count = 0;
+	stat->wakeup_count = 0;
+	stat->total_time = ktime_set(0, 0);
+	stat->prevent_suspend_time = ktime_set(0, 0);
+	stat->max_time = ktime_set(0, 0);
+	stat->last_time = ktime_set(0, 0);
+}
+
+static void init_dropped_suspend_blockers(void)
+{
+	suspend_blocker_stat_init(&dropped_suspend_blockers);
+}
+
+static void suspend_blocker_stat_drop(struct suspend_blocker_stats *stat)
+{
+	if (!stat->count)
+		return;
+
+	dropped_suspend_blockers.count += stat->count;
+	dropped_suspend_blockers.total_time = ktime_add(
+		dropped_suspend_blockers.total_time, stat->total_time);
+	dropped_suspend_blockers.prevent_suspend_time = ktime_add(
+		dropped_suspend_blockers.prevent_suspend_time,
+		stat->prevent_suspend_time);
+	dropped_suspend_blockers.max_time = ktime_add(
+		dropped_suspend_blockers.max_time, stat->max_time);
+}
+
+static void suspend_unblock_stat(struct suspend_blocker *blocker)
+{
+	struct suspend_blocker_stats *stat = &blocker->stat;
+	ktime_t duration;
+	ktime_t now;
+
+	if (!(blocker->flags & SB_ACTIVE))
+		return;
+
+	now = ktime_get();
+	stat->count++;
+	duration = ktime_sub(now, stat->last_time);
+	stat->total_time = ktime_add(stat->total_time, duration);
+	if (ktime_to_ns(duration) > ktime_to_ns(stat->max_time))
+		stat->max_time = duration;
+
+	stat->last_time = ktime_get();
+	if (blocker->flags & SB_PREVENTING_SUSPEND) {
+		duration = ktime_sub(now, last_sleep_time_update);
+		stat->prevent_suspend_time = ktime_add(
+			stat->prevent_suspend_time, duration);
+		blocker->flags &= ~SB_PREVENTING_SUSPEND;
+	}
+}
+
+static void suspend_block_stat(struct suspend_blocker *blocker)
+{
+	if (wait_for_wakeup) {
+		if (debug_mask & DEBUG_WAKEUP)
+			pr_info("wakeup suspend blocker: %s\n", blocker->name);
+
+		wait_for_wakeup = false;
+		blocker->stat.wakeup_count++;
+	}
+	if (!(blocker->flags & SB_ACTIVE))
+		blocker->stat.last_time = ktime_get();
+}
+
+static void update_sleep_wait_stats(bool done)
+{
+	struct suspend_blocker *blocker;
+	ktime_t now, elapsed, add;
+
+	now = ktime_get();
+	elapsed = ktime_sub(now, last_sleep_time_update);
+	list_for_each_entry(blocker, &active_blockers, link) {
+		struct suspend_blocker_stats *stat = &blocker->stat;
+
+		if (blocker->flags & SB_PREVENTING_SUSPEND) {
+			add = elapsed;
+			stat->prevent_suspend_time = ktime_add(
+				stat->prevent_suspend_time, add);
+		}
+		if (done)
+			blocker->flags &= ~SB_PREVENTING_SUSPEND;
+		else
+			blocker->flags |= SB_PREVENTING_SUSPEND;
+	}
+	last_sleep_time_update = now;
+}
+
+void about_to_enter_suspend(void)
+{
+	wait_for_wakeup = true;
+}
+
+#else /* !CONFIG_SUSPEND_BLOCKER_STATS */
+
+static inline void init_dropped_suspend_blockers(void) {}
+static inline void suspend_blocker_stat_init(struct suspend_blocker_stats *s) {}
+static inline void suspend_blocker_stat_drop(struct suspend_blocker_stats *s) {}
+static inline void suspend_unblock_stat(struct suspend_blocker *blocker) {}
+static inline void suspend_block_stat(struct suspend_blocker *blocker) {}
+static inline void update_sleep_wait_stats(bool done) {}
+#endif /* !CONFIG_SUSPEND_BLOCKER_STATS */
+
 #define pr_info_time(fmt, args...) \
 	do { \
 		struct timespec ts; \
@@ -140,6 +252,8 @@ void suspend_blocker_register(struct suspend_blocker *blocker)
 	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
 		pr_info("%s: Registering %s\n", __func__, blocker->name);
 
+	suspend_blocker_stat_init(&blocker->stat);
+
 	blocker->flags = SB_INITIALIZED;
 	INIT_LIST_HEAD(&blocker->link);
 
@@ -177,6 +291,10 @@ void suspend_blocker_unregister(struct suspend_blocker *blocker)
 		return;
 
 	spin_lock_irqsave(&list_lock, irqflags);
+
+	suspend_unblock_stat(blocker);
+	suspend_blocker_stat_drop(&blocker->stat);
+
 	blocker->flags &= ~SB_INITIALIZED;
 	list_del(&blocker->link);
 	if ((blocker->flags & SB_ACTIVE) && list_empty(&active_blockers))
@@ -206,11 +324,18 @@ void suspend_block(struct suspend_blocker *blocker)
 	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
 		pr_info("%s: %s\n", __func__, blocker->name);
 
+	suspend_block_stat(blocker);
+
 	blocker->flags |= SB_ACTIVE;
 	list_move(&blocker->link, &active_blockers);
 
 	current_event_num++;
 
+	if (blocker == &main_suspend_blocker)
+		update_sleep_wait_stats(true);
+	else if (!suspend_blocker_is_active(&main_suspend_blocker))
+		update_sleep_wait_stats(false);
+
 	spin_unlock_irqrestore(&list_lock, irqflags);
 }
 EXPORT_SYMBOL(suspend_block);
@@ -235,13 +360,19 @@ void suspend_unblock(struct suspend_blocker *blocker)
 	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
 		pr_info("%s: %s\n", __func__, blocker->name);
 
+	suspend_unblock_stat(blocker);
+
 	list_move(&blocker->link, &inactive_blockers);
 	if ((blocker->flags & SB_ACTIVE) && list_empty(&active_blockers))
 		queue_work(pm_wq, &suspend_work);
 	blocker->flags &= ~(SB_ACTIVE);
 
-	if ((debug_mask & DEBUG_SUSPEND) && blocker == &main_suspend_blocker)
-		print_active_suspend_blockers();
+	if (blocker == &main_suspend_blocker) {
+		if (debug_mask & DEBUG_SUSPEND)
+			print_active_suspend_blockers();
+
+		update_sleep_wait_stats(false);
+	}
 
 	spin_unlock_irqrestore(&list_lock, irqflags);
 }
@@ -297,10 +428,68 @@ void __init opportunistic_suspend_init(void)
 	suspend_blocker_register(&main_suspend_blocker);
 	suspend_block(&main_suspend_blocker);
 	suspend_blocker_register(&unknown_wakeup);
+	init_dropped_suspend_blockers();
 }
 
 static struct dentry *suspend_blocker_stats_dentry;
 
+#ifdef CONFIG_SUSPEND_BLOCKER_STATS
+static int print_blocker_stats(struct seq_file *m, const char *name,
+				struct suspend_blocker_stats *stat, int flags)
+{
+	int lock_count = stat->count;
+	ktime_t active_time = ktime_set(0, 0);
+	ktime_t total_time = stat->total_time;
+	ktime_t max_time = stat->max_time;
+	ktime_t prevent_suspend_time = stat->prevent_suspend_time;
+
+	if (flags & SB_ACTIVE) {
+		ktime_t now, add_time;
+
+		now = ktime_get();
+		add_time = ktime_sub(now, stat->last_time);
+		lock_count++;
+		active_time = add_time;
+		total_time = ktime_add(total_time, add_time);
+		if (flags & SB_PREVENTING_SUSPEND)
+			prevent_suspend_time = ktime_add(prevent_suspend_time,
+					ktime_sub(now, last_sleep_time_update));
+		if (add_time.tv64 > max_time.tv64)
+			max_time = add_time;
+	}
+
+	return seq_printf(m, "\"%s\"\t%d\t%d\t%lld\t%lld\t%lld\t%lld\t%lld\n",
+			name, lock_count, stat->wakeup_count,
+			ktime_to_ns(active_time), ktime_to_ns(total_time),
+			ktime_to_ns(prevent_suspend_time),
+			ktime_to_ns(max_time),
+			ktime_to_ns(stat->last_time));
+}
+
+static int suspend_blocker_stats_show(struct seq_file *m, void *unused)
+{
+	unsigned long irqflags;
+	struct suspend_blocker *blocker;
+
+	seq_puts(m, "name\tcount\twake_count\tactive_since"
+		 "\ttotal_time\tsleep_time\tmax_time\tlast_change\n");
+
+	spin_lock_irqsave(&list_lock, irqflags);
+	list_for_each_entry(blocker, &active_blockers, link)
+		print_blocker_stats(m,
+				blocker->name, &blocker->stat, blocker->flags);
+
+	list_for_each_entry(blocker, &inactive_blockers, link)
+		print_blocker_stats(m,
+				blocker->name, &blocker->stat, blocker->flags);
+
+	print_blocker_stats(m, "deleted", &dropped_suspend_blockers, 0);
+	spin_unlock_irqrestore(&list_lock, irqflags);
+	return 0;
+}
+
+#else
+
 static int suspend_blocker_stats_show(struct seq_file *m, void *unused)
 {
 	unsigned long irqflags;
@@ -316,6 +505,8 @@ static int suspend_blocker_stats_show(struct seq_file *m, void *unused)
 	return 0;
 }
 
+#endif
+
 static int suspend_blocker_stats_open(struct inode *inode, struct file *file)
 {
 	return single_open(file, suspend_blocker_stats_show, NULL);
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 2e9cfd5..e13c975 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -245,3 +245,8 @@ extern void __init opportunistic_suspend_init(void);
 #else
 static inline void opportunistic_suspend_init(void) {}
 #endif
+#ifdef CONFIG_SUSPEND_BLOCKER_STATS
+void about_to_enter_suspend(void);
+#else
+static inline void about_to_enter_suspend(void) {}
+#endif
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 9eb3876..df694e7 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -158,8 +158,10 @@ static int suspend_enter(suspend_state_t state)
 
 	error = sysdev_suspend(PMSG_SUSPEND);
 	if (!error) {
-		if (!suspend_is_blocked() && !suspend_test(TEST_CORE))
+		if (!suspend_is_blocked() && !suspend_test(TEST_CORE)) {
+			about_to_enter_suspend();
 			error = suspend_ops->enter(state);
+		}
 		sysdev_resume();
 	}
 
-- 
1.6.5.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 5/8] PM: suspend_block: Add suspend_blocker stats
  2010-04-30 22:36       ` [PATCH 4/8] PM: suspend_block: Add debugfs file Arve Hjønnevåg
@ 2010-04-30 22:36         ` Arve Hjønnevåg
  0 siblings, 0 replies; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-04-30 22:36 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Rafael J. Wysocki, Alan Stern, Tejun Heo, Oleg Nesterov,
	Arve Hjønnevåg, Pavel Machek, Len Brown, Jesse Barnes,
	Magnus Damm, Wu Fengguang, Andrew Morton, Maxim Levitsky

Report suspend block stats in /sys/kernel/debug/suspend_blockers.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 include/linux/suspend_blocker.h |   21 ++++-
 kernel/power/Kconfig            |    7 ++
 kernel/power/power.h            |    5 +
 kernel/power/suspend.c          |    4 +-
 kernel/power/suspend_blocker.c  |  190 +++++++++++++++++++++++++++++++++++++--
 5 files changed, 218 insertions(+), 9 deletions(-)

diff --git a/include/linux/suspend_blocker.h b/include/linux/suspend_blocker.h
index f9928cc..c80764c 100755
--- a/include/linux/suspend_blocker.h
+++ b/include/linux/suspend_blocker.h
@@ -17,12 +17,21 @@
 #define _LINUX_SUSPEND_BLOCKER_H
 
 #include <linux/list.h>
+#include <linux/ktime.h>
 
 /**
  * struct suspend_blocker - the basic suspend_blocker structure
  * @link:	List entry for active or inactive list.
- * @flags:	Tracks initialized and active state.
+ * @flags:	Tracks initialized, active and stats state.
  * @name:	Name used for debugging.
+ * @count:	Number of times this blocker has been deacivated
+ * @wakeup_count: Number of times this blocker was the first to block suspend
+ *		after resume.
+ * @total_time:	Total time this suspend blocker has prevented suspend.
+ * @prevent_suspend_time: Time this suspend blocker has prevented suspend while
+ *		user-space requested suspend.
+ * @max_time:	Max time this suspend blocker has been continuously active
+ * @last_time:	Monotonic clock when the active state last changed.
  *
  * When a suspend_blocker is active it prevents the system from entering
  * opportunistic suspend.
@@ -35,6 +44,16 @@ struct suspend_blocker {
 	struct list_head    link;
 	int                 flags;
 	const char         *name;
+#ifdef CONFIG_SUSPEND_BLOCKER_STATS
+	struct {
+		int             count;
+		int             wakeup_count;
+		ktime_t         total_time;
+		ktime_t         prevent_suspend_time;
+		ktime_t         max_time;
+		ktime_t         last_time;
+	} stat;
+#endif
 #endif
 };
 
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index fe5a2f2..4bcba07 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -146,6 +146,13 @@ config OPPORTUNISTIC_SUSPEND
 	  determines the sleep state the system will be put into when there are
 	  no active suspend blockers.
 
+config SUSPEND_BLOCKER_STATS
+	bool "Suspend block stats"
+	depends on OPPORTUNISTIC_SUSPEND
+	default y
+	---help---
+	  Report suspend block stats in /sys/kernel/debug/suspend_blockers
+
 config USER_SUSPEND_BLOCKERS
 	bool "Userspace suspend blockers"
 	depends on OPPORTUNISTIC_SUSPEND
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 67d10fd..897c116 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -245,3 +245,8 @@ extern void __init suspend_block_init(void);
 #else
 static inline void suspend_block_init(void) {}
 #endif
+#ifdef CONFIG_SUSPEND_BLOCKER_STATS
+void about_to_enter_suspend(void);
+#else
+static inline void about_to_enter_suspend(void) {}
+#endif
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index dc42006..6d327ea 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -159,8 +159,10 @@ static int suspend_enter(suspend_state_t state)
 
 	error = sysdev_suspend(PMSG_SUSPEND);
 	if (!error) {
-		if (!suspend_is_blocked() && !suspend_test(TEST_CORE))
+		if (!suspend_is_blocked() && !suspend_test(TEST_CORE)) {
+			about_to_enter_suspend();
 			error = suspend_ops->enter(state);
+		}
 		sysdev_resume();
 	}
 
diff --git a/kernel/power/suspend_blocker.c b/kernel/power/suspend_blocker.c
index ced4993..77920e6 100644
--- a/kernel/power/suspend_blocker.c
+++ b/kernel/power/suspend_blocker.c
@@ -34,6 +34,7 @@ module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
 
 #define SB_INITIALIZED            (1U << 8)
 #define SB_ACTIVE                 (1U << 9)
+#define SB_PREVENTING_SUSPEND     (1U << 10)
 
 static DEFINE_SPINLOCK(list_lock);
 static DEFINE_SPINLOCK(state_lock);
@@ -43,6 +44,7 @@ static int current_event_num;
 struct suspend_blocker main_suspend_blocker;
 static suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
 static bool enable_suspend_blockers;
+static struct suspend_blocker unknown_wakeup;
 static struct dentry *suspend_blocker_stats_dentry;
 
 #define pr_info_time(fmt, args...) \
@@ -57,6 +59,153 @@ static struct dentry *suspend_blocker_stats_dentry;
 			tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); \
 	} while (0);
 
+#ifdef CONFIG_SUSPEND_BLOCKER_STATS
+static struct suspend_blocker deleted_suspend_blockers;
+static ktime_t last_sleep_time_update;
+static bool wait_for_wakeup;
+
+static int print_blocker_stat(struct seq_file *m,
+			      struct suspend_blocker *blocker)
+{
+	int lock_count = blocker->stat.count;
+	ktime_t active_time = ktime_set(0, 0);
+	ktime_t total_time = blocker->stat.total_time;
+	ktime_t max_time = blocker->stat.max_time;
+	ktime_t prevent_suspend_time = blocker->stat.prevent_suspend_time;
+	if (blocker->flags & SB_ACTIVE) {
+		ktime_t now, add_time;
+		now = ktime_get();
+		add_time = ktime_sub(now, blocker->stat.last_time);
+		lock_count++;
+		active_time = add_time;
+		total_time = ktime_add(total_time, add_time);
+		if (blocker->flags & SB_PREVENTING_SUSPEND)
+			prevent_suspend_time = ktime_add(prevent_suspend_time,
+					ktime_sub(now, last_sleep_time_update));
+		if (add_time.tv64 > max_time.tv64)
+			max_time = add_time;
+	}
+
+	return seq_printf(m, "\"%s\"\t%d\t%d\t%lld\t%lld\t%lld\t%lld\t%lld\n",
+		       blocker->name, lock_count, blocker->stat.wakeup_count,
+		       ktime_to_ns(active_time), ktime_to_ns(total_time),
+		       ktime_to_ns(prevent_suspend_time), ktime_to_ns(max_time),
+		       ktime_to_ns(blocker->stat.last_time));
+}
+
+
+static int suspend_blocker_stats_show(struct seq_file *m, void *unused)
+{
+	unsigned long irqflags;
+	struct suspend_blocker *blocker;
+
+	seq_puts(m, "name\tcount\twake_count\tactive_since"
+		 "\ttotal_time\tsleep_time\tmax_time\tlast_change\n");
+	spin_lock_irqsave(&list_lock, irqflags);
+	list_for_each_entry(blocker, &inactive_blockers, link)
+		print_blocker_stat(m, blocker);
+	list_for_each_entry(blocker, &active_blockers, link)
+		print_blocker_stat(m, blocker);
+	spin_unlock_irqrestore(&list_lock, irqflags);
+	return 0;
+}
+
+static void suspend_blocker_stat_init_locked(struct suspend_blocker *blocker)
+{
+	blocker->stat.count = 0;
+	blocker->stat.wakeup_count = 0;
+	blocker->stat.total_time = ktime_set(0, 0);
+	blocker->stat.prevent_suspend_time = ktime_set(0, 0);
+	blocker->stat.max_time = ktime_set(0, 0);
+	blocker->stat.last_time = ktime_set(0, 0);
+}
+
+static void suspend_blocker_stat_destroy_locked(struct suspend_blocker *bl)
+{
+	if (!bl->stat.count)
+		return;
+	deleted_suspend_blockers.stat.count += bl->stat.count;
+	deleted_suspend_blockers.stat.total_time = ktime_add(
+		deleted_suspend_blockers.stat.total_time, bl->stat.total_time);
+	deleted_suspend_blockers.stat.prevent_suspend_time = ktime_add(
+		deleted_suspend_blockers.stat.prevent_suspend_time,
+		bl->stat.prevent_suspend_time);
+	deleted_suspend_blockers.stat.max_time = ktime_add(
+		deleted_suspend_blockers.stat.max_time, bl->stat.max_time);
+}
+
+static void suspend_unblock_stat_locked(struct suspend_blocker *blocker)
+{
+	ktime_t duration;
+	ktime_t now;
+	if (!(blocker->flags & SB_ACTIVE))
+		return;
+	now = ktime_get();
+	blocker->stat.count++;
+	duration = ktime_sub(now, blocker->stat.last_time);
+	blocker->stat.total_time =
+		ktime_add(blocker->stat.total_time, duration);
+	if (ktime_to_ns(duration) > ktime_to_ns(blocker->stat.max_time))
+		blocker->stat.max_time = duration;
+	blocker->stat.last_time = ktime_get();
+	if (blocker->flags & SB_PREVENTING_SUSPEND) {
+		duration = ktime_sub(now, last_sleep_time_update);
+		blocker->stat.prevent_suspend_time = ktime_add(
+			blocker->stat.prevent_suspend_time, duration);
+		blocker->flags &= ~SB_PREVENTING_SUSPEND;
+	}
+}
+
+static void suspend_block_stat_locked(struct suspend_blocker *blocker)
+{
+	if (wait_for_wakeup) {
+		if (debug_mask & DEBUG_WAKEUP)
+			pr_info("wakeup suspend blocker: %s\n", blocker->name);
+		wait_for_wakeup = false;
+		blocker->stat.wakeup_count++;
+	}
+	if (!(blocker->flags & SB_ACTIVE))
+		blocker->stat.last_time = ktime_get();
+}
+
+static void update_sleep_wait_stats_locked(bool done)
+{
+	struct suspend_blocker *blocker;
+	ktime_t now, elapsed, add;
+
+	now = ktime_get();
+	elapsed = ktime_sub(now, last_sleep_time_update);
+	list_for_each_entry(blocker, &active_blockers, link) {
+		if (blocker->flags & SB_PREVENTING_SUSPEND) {
+			add = elapsed;
+			blocker->stat.prevent_suspend_time = ktime_add(
+				blocker->stat.prevent_suspend_time, add);
+		}
+		if (done)
+			blocker->flags &= ~SB_PREVENTING_SUSPEND;
+		else
+			blocker->flags |= SB_PREVENTING_SUSPEND;
+	}
+	last_sleep_time_update = now;
+}
+
+void about_to_enter_suspend(void)
+{
+	wait_for_wakeup = true;
+}
+
+#else
+
+static inline void suspend_blocker_stat_init_locked(
+					struct suspend_blocker *blocker) {}
+static inline void suspend_blocker_stat_destroy_locked(
+					struct suspend_blocker *blocker) {}
+static inline void suspend_block_stat_locked(
+					struct suspend_blocker *blocker) {}
+static inline void suspend_unblock_stat_locked(
+					struct suspend_blocker *blocker) {}
+static inline void update_sleep_wait_stats_locked(bool done) {}
+
 static int suspend_blocker_stats_show(struct seq_file *m, void *unused)
 {
 	unsigned long irqflags;
@@ -72,6 +221,8 @@ static int suspend_blocker_stats_show(struct seq_file *m, void *unused)
 	return 0;
 }
 
+#endif
+
 static void print_active_blockers_locked(void)
 {
 	struct suspend_blocker *blocker;
@@ -102,20 +253,31 @@ static void suspend_worker(struct work_struct *work)
 	int entry_event_num;
 
 	enable_suspend_blockers = true;
-	while (!suspend_is_blocked()) {
-		entry_event_num = current_event_num;
 
+	if (suspend_is_blocked()) {
 		if (debug_mask & DEBUG_SUSPEND)
-			pr_info("suspend: enter suspend\n");
+			pr_info("suspend: abort suspend\n");
+		goto abort;
+	}
+
+	entry_event_num = current_event_num;
 
-		ret = pm_suspend(requested_suspend_state);
+	if (debug_mask & DEBUG_SUSPEND)
+		pr_info("suspend: enter suspend\n");
 
-		if (debug_mask & DEBUG_EXIT_SUSPEND)
-			pr_info_time("suspend: exit suspend, ret = %d ", ret);
+	ret = pm_suspend(requested_suspend_state);
 
-		if (current_event_num == entry_event_num)
+	if (debug_mask & DEBUG_EXIT_SUSPEND)
+		pr_info_time("suspend: exit suspend, ret = %d ", ret);
+
+	if (current_event_num == entry_event_num) {
+		if (debug_mask & DEBUG_SUSPEND)
 			pr_info("suspend: pm_suspend returned with no event\n");
+
+		suspend_block(&unknown_wakeup);
+		suspend_unblock(&unknown_wakeup);
 	}
+abort:
 	enable_suspend_blockers = false;
 }
 static DECLARE_WORK(suspend_work, suspend_worker);
@@ -142,6 +304,7 @@ void suspend_blocker_init(struct suspend_blocker *blocker, const char *name)
 	INIT_LIST_HEAD(&blocker->link);
 
 	spin_lock_irqsave(&list_lock, irqflags);
+	suspend_blocker_stat_init_locked(blocker);
 	list_add(&blocker->link, &inactive_blockers);
 	spin_unlock_irqrestore(&list_lock, irqflags);
 }
@@ -161,6 +324,7 @@ void suspend_blocker_destroy(struct suspend_blocker *blocker)
 		pr_info("suspend_blocker_destroy name=%s\n", blocker->name);
 
 	spin_lock_irqsave(&list_lock, irqflags);
+	suspend_blocker_stat_destroy_locked(blocker);
 	blocker->flags &= ~SB_INITIALIZED;
 	list_del(&blocker->link);
 	if ((blocker->flags & SB_ACTIVE) && list_empty(&active_blockers))
@@ -187,9 +351,14 @@ void suspend_block(struct suspend_blocker *blocker)
 	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
 		pr_info("suspend_block: %s\n", blocker->name);
 
+	suspend_block_stat_locked(blocker);
 	blocker->flags |= SB_ACTIVE;
 	list_move(&blocker->link, &active_blockers);
 	current_event_num++;
+	if (blocker == &main_suspend_blocker)
+		update_sleep_wait_stats_locked(true);
+	else if (!suspend_blocker_is_active(&main_suspend_blocker))
+		update_sleep_wait_stats_locked(false);
 
 	spin_unlock_irqrestore(&list_lock, irqflags);
 }
@@ -215,6 +384,7 @@ void suspend_unblock(struct suspend_blocker *blocker)
 	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
 		pr_info("suspend_unblock: %s\n", blocker->name);
 
+	suspend_unblock_stat_locked(blocker);
 	list_move(&blocker->link, &inactive_blockers);
 
 	if ((blocker->flags & SB_ACTIVE) && list_empty(&active_blockers))
@@ -223,6 +393,7 @@ void suspend_unblock(struct suspend_blocker *blocker)
 	if (blocker == &main_suspend_blocker) {
 		if (debug_mask & DEBUG_SUSPEND)
 			print_active_blockers_locked();
+		update_sleep_wait_stats_locked(false);
 	}
 	spin_unlock_irqrestore(&list_lock, irqflags);
 }
@@ -288,6 +459,11 @@ void __init suspend_block_init(void)
 {
 	suspend_blocker_init(&main_suspend_blocker, "main");
 	suspend_block(&main_suspend_blocker);
+	suspend_blocker_init(&unknown_wakeup, "unknown_wakeups");
+#ifdef CONFIG_SUSPEND_BLOCKER_STATS
+	suspend_blocker_init(&deleted_suspend_blockers,
+				"deleted_suspend_blockers");
+#endif
 }
 
 static int __init suspend_block_postcore_init(void)
-- 
1.6.5.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 5/8] PM: suspend_block: Add suspend_blocker stats
  2010-04-28  4:31       ` [PATCH 4/8] PM: suspend_block: Add debugfs file Arve Hjønnevåg
@ 2010-04-28  4:31         ` Arve Hjønnevåg
  0 siblings, 0 replies; 53+ messages in thread
From: Arve Hjønnevåg @ 2010-04-28  4:31 UTC (permalink / raw)
  To: linux-pm, linux-kernel
  Cc: Rafael J. Wysocki, Alan Stern, Tejun Heo, Oleg Nesterov,
	Arve Hjønnevåg, Pavel Machek, Len Brown, Jesse Barnes,
	Magnus Damm, Wu Fengguang, Andrew Morton, Maxim Levitsky

Report suspend block stats in /sys/kernel/debug/suspend_blockers.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
---
 include/linux/suspend_blocker.h |   21 ++++-
 kernel/power/Kconfig            |    7 ++
 kernel/power/power.h            |    6 +-
 kernel/power/suspend.c          |    4 +-
 kernel/power/suspend_blocker.c  |  191 +++++++++++++++++++++++++++++++++++++--
 5 files changed, 219 insertions(+), 10 deletions(-)

diff --git a/include/linux/suspend_blocker.h b/include/linux/suspend_blocker.h
index f9928cc..c80764c 100755
--- a/include/linux/suspend_blocker.h
+++ b/include/linux/suspend_blocker.h
@@ -17,12 +17,21 @@
 #define _LINUX_SUSPEND_BLOCKER_H
 
 #include <linux/list.h>
+#include <linux/ktime.h>
 
 /**
  * struct suspend_blocker - the basic suspend_blocker structure
  * @link:	List entry for active or inactive list.
- * @flags:	Tracks initialized and active state.
+ * @flags:	Tracks initialized, active and stats state.
  * @name:	Name used for debugging.
+ * @count:	Number of times this blocker has been deacivated
+ * @wakeup_count: Number of times this blocker was the first to block suspend
+ *		after resume.
+ * @total_time:	Total time this suspend blocker has prevented suspend.
+ * @prevent_suspend_time: Time this suspend blocker has prevented suspend while
+ *		user-space requested suspend.
+ * @max_time:	Max time this suspend blocker has been continuously active
+ * @last_time:	Monotonic clock when the active state last changed.
  *
  * When a suspend_blocker is active it prevents the system from entering
  * opportunistic suspend.
@@ -35,6 +44,16 @@ struct suspend_blocker {
 	struct list_head    link;
 	int                 flags;
 	const char         *name;
+#ifdef CONFIG_SUSPEND_BLOCKER_STATS
+	struct {
+		int             count;
+		int             wakeup_count;
+		ktime_t         total_time;
+		ktime_t         prevent_suspend_time;
+		ktime_t         max_time;
+		ktime_t         last_time;
+	} stat;
+#endif
 #endif
 };
 
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index fe5a2f2..4bcba07 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -146,6 +146,13 @@ config OPPORTUNISTIC_SUSPEND
 	  determines the sleep state the system will be put into when there are
 	  no active suspend blockers.
 
+config SUSPEND_BLOCKER_STATS
+	bool "Suspend block stats"
+	depends on OPPORTUNISTIC_SUSPEND
+	default y
+	---help---
+	  Report suspend block stats in /sys/kernel/debug/suspend_blockers
+
 config USER_SUSPEND_BLOCKERS
 	bool "Userspace suspend blockers"
 	depends on OPPORTUNISTIC_SUSPEND
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 9b468d7..75b8849 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -240,4 +240,8 @@ static inline void suspend_thaw_processes(void)
 /* kernel/power/suspend_block.c */
 extern int request_suspend_state(suspend_state_t state);
 extern bool request_suspend_valid_state(suspend_state_t state);
-
+#ifdef CONFIG_SUSPEND_BLOCKER_STATS
+void about_to_enter_suspend(void);
+#else
+static inline void about_to_enter_suspend(void) {}
+#endif
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index dc42006..6d327ea 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -159,8 +159,10 @@ static int suspend_enter(suspend_state_t state)
 
 	error = sysdev_suspend(PMSG_SUSPEND);
 	if (!error) {
-		if (!suspend_is_blocked() && !suspend_test(TEST_CORE))
+		if (!suspend_is_blocked() && !suspend_test(TEST_CORE)) {
+			about_to_enter_suspend();
 			error = suspend_ops->enter(state);
+		}
 		sysdev_resume();
 	}
 
diff --git a/kernel/power/suspend_blocker.c b/kernel/power/suspend_blocker.c
index ee43490..2d43f37 100644
--- a/kernel/power/suspend_blocker.c
+++ b/kernel/power/suspend_blocker.c
@@ -32,6 +32,7 @@ module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
 
 #define SB_INITIALIZED            (1U << 8)
 #define SB_ACTIVE                 (1U << 9)
+#define SB_PREVENTING_SUSPEND     (1U << 10)
 
 static DEFINE_SPINLOCK(list_lock);
 static DEFINE_SPINLOCK(state_lock);
@@ -42,6 +43,7 @@ struct workqueue_struct *suspend_work_queue;
 struct suspend_blocker main_suspend_blocker;
 static suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
 static bool enable_suspend_blockers;
+static struct suspend_blocker unknown_wakeup;
 static struct dentry *suspend_blocker_stats_dentry;
 
 #define pr_info_time(fmt, args...) \
@@ -56,6 +58,153 @@ static struct dentry *suspend_blocker_stats_dentry;
 			tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); \
 	} while (0);
 
+#ifdef CONFIG_SUSPEND_BLOCKER_STATS
+static struct suspend_blocker deleted_suspend_blockers;
+static ktime_t last_sleep_time_update;
+static bool wait_for_wakeup;
+
+static int print_blocker_stat(struct seq_file *m,
+			      struct suspend_blocker *blocker)
+{
+	int lock_count = blocker->stat.count;
+	ktime_t active_time = ktime_set(0, 0);
+	ktime_t total_time = blocker->stat.total_time;
+	ktime_t max_time = blocker->stat.max_time;
+	ktime_t prevent_suspend_time = blocker->stat.prevent_suspend_time;
+	if (blocker->flags & SB_ACTIVE) {
+		ktime_t now, add_time;
+		now = ktime_get();
+		add_time = ktime_sub(now, blocker->stat.last_time);
+		lock_count++;
+		active_time = add_time;
+		total_time = ktime_add(total_time, add_time);
+		if (blocker->flags & SB_PREVENTING_SUSPEND)
+			prevent_suspend_time = ktime_add(prevent_suspend_time,
+					ktime_sub(now, last_sleep_time_update));
+		if (add_time.tv64 > max_time.tv64)
+			max_time = add_time;
+	}
+
+	return seq_printf(m, "\"%s\"\t%d\t%d\t%lld\t%lld\t%lld\t%lld\t%lld\n",
+		       blocker->name, lock_count, blocker->stat.wakeup_count,
+		       ktime_to_ns(active_time), ktime_to_ns(total_time),
+		       ktime_to_ns(prevent_suspend_time), ktime_to_ns(max_time),
+		       ktime_to_ns(blocker->stat.last_time));
+}
+
+
+static int suspend_blocker_stats_show(struct seq_file *m, void *unused)
+{
+	unsigned long irqflags;
+	struct suspend_blocker *blocker;
+
+	seq_puts(m, "name\tcount\twake_count\tactive_since"
+		 "\ttotal_time\tsleep_time\tmax_time\tlast_change\n");
+	spin_lock_irqsave(&list_lock, irqflags);
+	list_for_each_entry(blocker, &inactive_blockers, link)
+		print_blocker_stat(m, blocker);
+	list_for_each_entry(blocker, &active_blockers, link)
+		print_blocker_stat(m, blocker);
+	spin_unlock_irqrestore(&list_lock, irqflags);
+	return 0;
+}
+
+static void suspend_blocker_stat_init_locked(struct suspend_blocker *blocker)
+{
+	blocker->stat.count = 0;
+	blocker->stat.wakeup_count = 0;
+	blocker->stat.total_time = ktime_set(0, 0);
+	blocker->stat.prevent_suspend_time = ktime_set(0, 0);
+	blocker->stat.max_time = ktime_set(0, 0);
+	blocker->stat.last_time = ktime_set(0, 0);
+}
+
+static void suspend_blocker_stat_destroy_locked(struct suspend_blocker *bl)
+{
+	if (!bl->stat.count)
+		return;
+	deleted_suspend_blockers.stat.count += bl->stat.count;
+	deleted_suspend_blockers.stat.total_time = ktime_add(
+		deleted_suspend_blockers.stat.total_time, bl->stat.total_time);
+	deleted_suspend_blockers.stat.prevent_suspend_time = ktime_add(
+		deleted_suspend_blockers.stat.prevent_suspend_time,
+		bl->stat.prevent_suspend_time);
+	deleted_suspend_blockers.stat.max_time = ktime_add(
+		deleted_suspend_blockers.stat.max_time, bl->stat.max_time);
+}
+
+static void suspend_unblock_stat_locked(struct suspend_blocker *blocker)
+{
+	ktime_t duration;
+	ktime_t now;
+	if (!(blocker->flags & SB_ACTIVE))
+		return;
+	now = ktime_get();
+	blocker->stat.count++;
+	duration = ktime_sub(now, blocker->stat.last_time);
+	blocker->stat.total_time =
+		ktime_add(blocker->stat.total_time, duration);
+	if (ktime_to_ns(duration) > ktime_to_ns(blocker->stat.max_time))
+		blocker->stat.max_time = duration;
+	blocker->stat.last_time = ktime_get();
+	if (blocker->flags & SB_PREVENTING_SUSPEND) {
+		duration = ktime_sub(now, last_sleep_time_update);
+		blocker->stat.prevent_suspend_time = ktime_add(
+			blocker->stat.prevent_suspend_time, duration);
+		blocker->flags &= ~SB_PREVENTING_SUSPEND;
+	}
+}
+
+static void suspend_block_stat_locked(struct suspend_blocker *blocker)
+{
+	if (wait_for_wakeup) {
+		if (debug_mask & DEBUG_WAKEUP)
+			pr_info("wakeup suspend blocker: %s\n", blocker->name);
+		wait_for_wakeup = false;
+		blocker->stat.wakeup_count++;
+	}
+	if (!(blocker->flags & SB_ACTIVE))
+		blocker->stat.last_time = ktime_get();
+}
+
+static void update_sleep_wait_stats_locked(bool done)
+{
+	struct suspend_blocker *blocker;
+	ktime_t now, elapsed, add;
+
+	now = ktime_get();
+	elapsed = ktime_sub(now, last_sleep_time_update);
+	list_for_each_entry(blocker, &active_blockers, link) {
+		if (blocker->flags & SB_PREVENTING_SUSPEND) {
+			add = elapsed;
+			blocker->stat.prevent_suspend_time = ktime_add(
+				blocker->stat.prevent_suspend_time, add);
+		}
+		if (done)
+			blocker->flags &= ~SB_PREVENTING_SUSPEND;
+		else
+			blocker->flags |= SB_PREVENTING_SUSPEND;
+	}
+	last_sleep_time_update = now;
+}
+
+void about_to_enter_suspend(void)
+{
+	wait_for_wakeup = true;
+}
+
+#else
+
+static inline void suspend_blocker_stat_init_locked(
+					struct suspend_blocker *blocker) {}
+static inline void suspend_blocker_stat_destroy_locked(
+					struct suspend_blocker *blocker) {}
+static inline void suspend_block_stat_locked(
+					struct suspend_blocker *blocker) {}
+static inline void suspend_unblock_stat_locked(
+					struct suspend_blocker *blocker) {}
+static inline void update_sleep_wait_stats_locked(bool done) {}
+
 static int suspend_blocker_stats_show(struct seq_file *m, void *unused)
 {
 	unsigned long irqflags;
@@ -71,6 +220,8 @@ static int suspend_blocker_stats_show(struct seq_file *m, void *unused)
 	return 0;
 }
 
+#endif
+
 static void print_active_blockers_locked(void)
 {
 	struct suspend_blocker *blocker;
@@ -101,20 +252,31 @@ static void suspend_worker(struct work_struct *work)
 	int entry_event_num;
 
 	enable_suspend_blockers = true;
-	while (!suspend_is_blocked()) {
-		entry_event_num = current_event_num;
 
+	if (suspend_is_blocked()) {
 		if (debug_mask & DEBUG_SUSPEND)
-			pr_info("suspend: enter suspend\n");
+			pr_info("suspend: abort suspend\n");
+		goto abort;
+	}
+
+	entry_event_num = current_event_num;
+
+	if (debug_mask & DEBUG_SUSPEND)
+		pr_info("suspend: enter suspend\n");
 
-		ret = pm_suspend(requested_suspend_state);
+	ret = pm_suspend(requested_suspend_state);
 
-		if (debug_mask & DEBUG_EXIT_SUSPEND)
-			pr_info_time("suspend: exit suspend, ret = %d ", ret);
+	if (debug_mask & DEBUG_EXIT_SUSPEND)
+		pr_info_time("suspend: exit suspend, ret = %d ", ret);
 
-		if (current_event_num == entry_event_num)
+	if (current_event_num == entry_event_num) {
+		if (debug_mask & DEBUG_SUSPEND)
 			pr_info("suspend: pm_suspend returned with no event\n");
+
+		suspend_block(&unknown_wakeup);
+		suspend_unblock(&unknown_wakeup);
 	}
+abort:
 	enable_suspend_blockers = false;
 }
 static DECLARE_WORK(suspend_work, suspend_worker);
@@ -141,6 +303,7 @@ void suspend_blocker_init(struct suspend_blocker *blocker, const char *name)
 	INIT_LIST_HEAD(&blocker->link);
 
 	spin_lock_irqsave(&list_lock, irqflags);
+	suspend_blocker_stat_init_locked(blocker);
 	list_add(&blocker->link, &inactive_blockers);
 	spin_unlock_irqrestore(&list_lock, irqflags);
 }
@@ -160,6 +323,7 @@ void suspend_blocker_destroy(struct suspend_blocker *blocker)
 		pr_info("suspend_blocker_destroy name=%s\n", blocker->name);
 
 	spin_lock_irqsave(&list_lock, irqflags);
+	suspend_blocker_stat_destroy_locked(blocker);
 	blocker->flags &= ~SB_INITIALIZED;
 	list_del(&blocker->link);
 	if ((blocker->flags & SB_ACTIVE) && list_empty(&active_blockers))
@@ -182,6 +346,7 @@ void suspend_block(struct suspend_blocker *blocker)
 		return;
 
 	spin_lock_irqsave(&list_lock, irqflags);
+	suspend_block_stat_locked(blocker);
 	blocker->flags |= SB_ACTIVE;
 	list_del(&blocker->link);
 
@@ -191,6 +356,10 @@ void suspend_block(struct suspend_blocker *blocker)
 	list_add(&blocker->link, &active_blockers);
 
 	current_event_num++;
+	if (blocker == &main_suspend_blocker)
+		update_sleep_wait_stats_locked(true);
+	else if (!suspend_blocker_is_active(&main_suspend_blocker))
+		update_sleep_wait_stats_locked(false);
 	spin_unlock_irqrestore(&list_lock, irqflags);
 }
 EXPORT_SYMBOL(suspend_block);
@@ -212,6 +381,8 @@ void suspend_unblock(struct suspend_blocker *blocker)
 
 	spin_lock_irqsave(&list_lock, irqflags);
 
+	suspend_unblock_stat_locked(blocker);
+
 	if (debug_mask & DEBUG_SUSPEND_BLOCKER)
 		pr_info("suspend_unblock: %s\n", blocker->name);
 
@@ -224,6 +395,7 @@ void suspend_unblock(struct suspend_blocker *blocker)
 	if (blocker == &main_suspend_blocker) {
 		if (debug_mask & DEBUG_SUSPEND)
 			print_active_blockers_locked();
+		update_sleep_wait_stats_locked(false);
 	}
 	spin_unlock_irqrestore(&list_lock, irqflags);
 }
@@ -293,6 +465,11 @@ static int __init suspend_block_init(void)
 
 	suspend_blocker_init(&main_suspend_blocker, "main");
 	suspend_block(&main_suspend_blocker);
+	suspend_blocker_init(&unknown_wakeup, "unknown_wakeups");
+#ifdef CONFIG_SUSPEND_BLOCKER_STATS
+	suspend_blocker_init(&deleted_suspend_blockers,
+				"deleted_suspend_blockers");
+#endif
 	return 0;
 }
 
-- 
1.6.5.1


^ permalink raw reply related	[flat|nested] 53+ messages in thread

end of thread, other threads:[~2010-05-27 15:40 UTC | newest]

Thread overview: 53+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-05-14  4:11 [PATCH 0/8] Suspend block api (version 7) Arve Hjønnevåg
2010-05-14  4:11 ` [PATCH 1/8] PM: Add suspend block api Arve Hjønnevåg
2010-05-14  4:11   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
2010-05-14  4:11     ` [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active Arve Hjønnevåg
2010-05-14  4:11       ` [PATCH 4/8] PM: suspend_block: Add debugfs file Arve Hjønnevåg
2010-05-14  4:11         ` [PATCH 5/8] PM: suspend_block: Add suspend_blocker stats Arve Hjønnevåg
2010-05-14  4:11           ` [PATCH 6/8] PM: Add suspend blocking work Arve Hjønnevåg
2010-05-14  4:11             ` [PATCH 7/8] Input: Block suspend while event queue is not empty Arve Hjønnevåg
2010-05-14  4:11               ` [PATCH 8/8] power_supply: Block suspend while power supply change notifications are pending Arve Hjønnevåg
2010-05-18 13:11   ` [PATCH 1/8] PM: Add suspend block api Pavel Machek
2010-05-20  9:11     ` Florian Mickler
2010-05-20  9:26       ` Florian Mickler
2010-05-20 22:18         ` Rafael J. Wysocki
2010-05-21  6:04           ` Florian Mickler
2010-05-27 15:41           ` Pavel Machek
2010-05-14 21:08 ` [PATCH 0/8] Suspend block api (version 7) Rafael J. Wysocki
2010-05-17  4:50   ` Arve Hjønnevåg
2010-05-17 19:01     ` Mike Snitzer
2010-05-17 21:42     ` Rafael J. Wysocki
2010-05-17 22:16       ` Kevin Hilman
2010-05-18  0:52       ` Arve Hjønnevåg
2010-05-18 16:18         ` Kevin Hilman
2010-05-18 18:52           ` Rafael J. Wysocki
2010-05-18 22:04             ` Kevin Hilman
2010-05-18 22:29               ` Rafael J. Wysocki
2010-05-19  0:00           ` Arve Hjønnevåg
2010-05-18 19:13         ` Rafael J. Wysocki
2010-05-18 20:47           ` Arve Hjønnevåg
2010-05-18 21:48             ` Rafael J. Wysocki
2010-05-18 22:03               ` Arve Hjønnevåg
2010-05-18 22:34                 ` Rafael J. Wysocki
2010-05-18 22:52                   ` Arve Hjønnevåg
2010-05-18 23:19                     ` Rafael J. Wysocki
2010-05-18 23:42                       ` Arve Hjønnevåg
2010-05-19 20:39                         ` Rafael J. Wysocki
2010-05-19 21:34                           ` Arve Hjønnevåg
2010-05-20 22:21                             ` Rafael J. Wysocki
2010-05-16 19:42 ` Rafael J. Wysocki
2010-05-17  4:16   ` Arve Hjønnevåg
2010-05-17 20:40     ` Rafael J. Wysocki
2010-05-17 20:51       ` Brian Swetland
2010-05-17 21:44         ` Rafael J. Wysocki
2010-05-17 23:32           ` Arve Hjønnevåg
2010-05-18 19:38             ` Rafael J. Wysocki
2010-05-18 20:35               ` Arve Hjønnevåg
2010-05-18 21:14                 ` Rafael J. Wysocki
2010-05-18 22:21                   ` Arve Hjønnevåg
2010-05-18 22:56                     ` Rafael J. Wysocki
2010-05-18 23:06                       ` Arve Hjønnevåg
2010-05-19 20:40                         ` Rafael J. Wysocki
  -- strict thread matches above, loose matches on Subject: below --
2010-05-21 22:46 [PATCH 0/8] Suspend block api (version 8) Arve Hjønnevåg
2010-05-21 22:46 ` [PATCH 1/8] PM: Opportunistic suspend support Arve Hjønnevåg
2010-05-21 22:46   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
2010-05-21 22:46     ` [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active Arve Hjønnevåg
2010-05-21 22:46       ` [PATCH 4/8] PM: suspend_block: Add debugfs file Arve Hjønnevåg
2010-05-21 22:46         ` [PATCH 5/8] PM: suspend_block: Add suspend_blocker stats Arve Hjønnevåg
2010-04-30 22:36 [PATCH 0/8] Suspend block api (version 6) Arve Hjønnevåg
2010-04-30 22:36 ` [PATCH 1/8] PM: Add suspend block api Arve Hjønnevåg
2010-04-30 22:36   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
2010-04-30 22:36     ` [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active Arve Hjønnevåg
2010-04-30 22:36       ` [PATCH 4/8] PM: suspend_block: Add debugfs file Arve Hjønnevåg
2010-04-30 22:36         ` [PATCH 5/8] PM: suspend_block: Add suspend_blocker stats Arve Hjønnevåg
2010-04-28  4:31 [PATCH 0/9] Suspend block api (version 5) Arve Hjønnevåg
2010-04-28  4:31 ` [PATCH 1/8] PM: Add suspend block api Arve Hjønnevåg
2010-04-28  4:31   ` [PATCH 2/8] PM: suspend_block: Add driver to access suspend blockers from user-space Arve Hjønnevåg
2010-04-28  4:31     ` [PATCH 3/8] PM: suspend_block: Abort task freezing if a suspend_blocker is active Arve Hjønnevåg
2010-04-28  4:31       ` [PATCH 4/8] PM: suspend_block: Add debugfs file Arve Hjønnevåg
2010-04-28  4:31         ` [PATCH 5/8] PM: suspend_block: Add suspend_blocker stats Arve Hjønnevåg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).