Skip to contentSkip to conversation

wake up notifications and suspend blocking (aka more wakelock stuff)]

RFC In review mark gross 2 participants 3 messages Oct 2, 2011 – Oct 4, 2011

Subsystems (4)
lore
Share & tools
lore

mark gross

author
#0 lore raw

RFC 1/1 wake up notifications and suspend blocking (aka more wakelock stuff)]

Forwarding to bigger group for discussion.

----- Forwarded message from mark gross <[email protected]> -----

Subject: Re: [RFC] wake up notifications and suspend blocking (aka more wakelock stuff)
Date: Tue, 20 Sep 2011 13:36:15 -0700
From: mark gross <[email protected]>
To: mark gross <[email protected]>
Reply-To: [email protected]
Cc: [email protected], [email protected], Alan Stern <[email protected]>, [email protected], [email protected], "Rafael J. Wysocki" <[email protected]>

Quoted 1 line

From a2615c59cb3b7632cf22e2c25a10b401e2151bbf Mon Sep 17 00:00:00 2001

From: mark gross <[email protected]>
Date: Mon, 19 Sep 2011 09:48:31 -0700
Subject: [PATCH 2/2] implement suspend bock pm_qos class such that whenever the
pm_qos_request is > 0 suspend to ram is blocked.

This is one of the 2 features the wakelock design attempts to implement. (the other is wake even notification consumption before re-entry into suspend)

---
 drivers/base/power/wakeup.c   |    5 +++--
 include/linux/pm_qos_params.h |    4 +++-
 kernel/pm_qos_params.c        |   14 +++++++++++++-
 kernel/power/suspend.c        |    7 +++++++
 4 files changed, 26 insertions(+), 4 deletions(-)
drivers/base/power/wakeup.c +3 -2
index eb300d7..790010d 100644
@@ -10,8 +10,8 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 #include <linux/capability.h>
-#include <linux/freezer.h>
 #include <linux/miscdevice.h>
+#include <linux/pm_qos_params.h>
 #include <linux/suspend.h>
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
@@ -791,7 +791,8 @@ bool pm_get_wakeup_count(unsigned int *count)
 
 	for (;;) {
 		split_counters(&cnt, &inpr);
-		if (inpr == 0 || signal_pending(current))
+		if (((pm_qos_request(PM_QOS_SUSPEND_BLOCK) < 1) && (inpr == 0))
+				|| signal_pending(current))
 			break;
 		pm_wakeup_update_hit_counts();
 		schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT));
include/linux/pm_qos_params.h +3 -1
index a7d87f9..19b771d 100644
@@ -12,13 +12,15 @@
 #define PM_QOS_CPU_DMA_LATENCY 1
 #define PM_QOS_NETWORK_LATENCY 2
 #define PM_QOS_NETWORK_THROUGHPUT 3
+#define PM_QOS_SUSPEND_BLOCK 4
 
-#define PM_QOS_NUM_CLASSES 4
+#define PM_QOS_NUM_CLASSES 5
 #define PM_QOS_DEFAULT_VALUE -1
 
 #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
 #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE	(2000 * USEC_PER_SEC)
 #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE	0
+#define PM_QOS_SUSPEND_BLOCK_DEFAULT_VALUE	0
 
 struct pm_qos_request_list {
 	struct plist_node list;
kernel/pm_qos_params.c +13 -1
index 37f05d0..838ca8a 100644
@@ -104,11 +104,23 @@ static struct pm_qos_object network_throughput_pm_qos = {
 };
 
 
+static BLOCKING_NOTIFIER_HEAD(suspend_block_notifier);
+static struct pm_qos_object suspend_block_pm_qos = {
+	.requests = PLIST_HEAD_INIT(suspend_block_pm_qos.requests),
+	.notifiers = &suspend_block_notifier,
+	.name = "suspend_block",
+	.target_value = PM_QOS_SUSPEND_BLOCK_DEFAULT_VALUE,
+	.default_value = PM_QOS_SUSPEND_BLOCK_DEFAULT_VALUE,
+	.type = PM_QOS_MAX,
+};
+
+
 static struct pm_qos_object *pm_qos_array[] = {
 	&null_pm_qos,
 	&cpu_dma_pm_qos,
 	&network_lat_pm_qos,
-	&network_throughput_pm_qos
+	&network_throughput_pm_qos,
+	&suspend_block_pm_qos
 };
 
 static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
kernel/power/suspend.c +7 -0
index b6b71ad..e71c8d7 100644
@@ -20,6 +20,7 @@
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/mm.h>
+#include <linux/pm_qos_params.h>
 #include <linux/slab.h>
 #include <linux/suspend.h>
 #include <linux/syscore_ops.h>
@@ -278,6 +279,12 @@ int enter_state(suspend_state_t state)
 	if (!valid_state(state))
 		return -ENODEV;
 
+	if (state == PM_SUSPEND_MEM)
+		if (0 < pm_qos_request(PM_QOS_SUSPEND_BLOCK)) {
+			WARN(1, "suspend blocked by pm_qos");
+			return -EBUSY;
+		}
+
 	if (!mutex_trylock(&pm_mutex))
 		return -EBUSY;
 
Signature · 4 lines
1.7.4.1


----- End forwarded message -----
#1 lore raw
Quoted 1 line · On Sun, 2 Oct 2011 09:48:49 -0700 mark gross <[email protected]> wrote:

Forwarding to bigger group for discussion.

Looks clean enough - only question I have is do we need a separate 'suspend block' or can latency do it -suspend is a very very high latency event. I guess the suspend block is clearer in intent than abusing latency but I do wonder if the actual suspend path should also check latency constraints too. If I've asked for 5mS latency then suspend is a wrong choice!

Alan

author
#2 lore raw
Quoted 12 lines · Alan Cox
Quoted 1 line · On Sun, 2 Oct 2011 09:48:49 -0700 mark gross <[email protected]> wrote:

Forwarding to bigger group for discussion.

Looks clean enough - only question I have is do we need a separate 'suspend block' or can latency do it -suspend is a very very high latency event. I guess the suspend block is clearer in intent than abusing latency but I do wonder if the actual suspend path should also check latency constraints too. If I've asked for 5mS latency then suspend is a wrong choice!

I don't think over loading the meaning of cpu_dma_latency would work well for this. If cpu_dma_latency constraint is > 5mS then EFAIL a suspend attempt? feels clunky.

If you use less than then anyone using a constraint (like some wifi and audio) would block suspend. also not so good.

The poster child for needing this is the USB gadget device with associated charging over USB. Here we can't sleep because we'd have a hard time meeting USB spec if we did. Also, we don't want to sleep while charging if charging is under OS control. (checking temperature is tricky while suspended.)

--mark