| Submitter | Falempe Jocelyn |
|---|---|
| Date | 2009-11-06 16:00:41 |
| Message ID | <1257523241.1318.367.camel@xhp836-11> |
| Download | mbox | patch |
| Permalink | /patch/58064/ |
| State | Not Applicable |
| Delegated to: | Kevin Hilman |
| Headers | show |
Comments
Hmm. This is an interesting approach. Just to understand the usecase better, though - my understanding is that Nokia's approach on Omap-based devices has been to treat "suspend" as a runtime state, without actually performing a systemwide transition. What are the constraints that make shifting into a different hardware state more efficient for you?
On Fri, 2009-11-06 at 17:03 +0000, Matthew Garrett wrote: > Hmm. This is an interesting approach. Just to understand the usecase > better, though - my understanding is that Nokia's approach on Omap-based > devices has been to treat "suspend" as a runtime state, without actually > performing a systemwide transition. What are the constraints that make > shifting into a different hardware state more efficient for you? > In fact we are doing "retention" in idle and with the suspend path. It's specific to Android, with the global suspend and wakelock framework. When all wakelocks are released (ie screen is black, no running app), the phone goes to suspend, which freeze userspace and also suspend the device driver. This way you can choose the wakeup sources, and stay in suspend during a long time (a few hours). Without this, you have to track down all user space app that wakeup the phone, and it is hard to sleep more than a few second. The drawback is that when you want to wakeup, it takes a lot of time to unfreeze the userspace, and resume all the device driver. This is what this feature address (for low-level wakeup only). But as this patch is not Android specific, I think other platforms may use it too. Best regards, Jocelyn -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Fri, Nov 06, 2009 at 06:42:21PM +0100, Falempe Jocelyn wrote: > In fact we are doing "retention" in idle and with the suspend path. It's > specific to Android, with the global suspend and wakelock framework. > When all wakelocks are released (ie screen is black, no running app), > the phone goes to suspend, which freeze userspace and also suspend the > device driver. This way you can choose the wakeup sources, and stay in > suspend during a long time (a few hours). Without this, you have to > track down all user space app that wakeup the phone, and it is hard to > sleep more than a few second. What's triggering the application wakeups? If it's just timeouts, can't you simply adjust the range timer slop so that the timeouts don't fire? > The drawback is that when you want to wakeup, it takes a lot of time to > unfreeze the userspace, and resume all the device driver. This is what > this feature address (for low-level wakeup only). > But as this patch is not Android specific, I think other platforms may > use it too. Yeah, I can certainly see the appeal if you have that constraint.
On Fri, 2009-11-06 at 18:09 +0000, Matthew Garrett wrote: > On Fri, Nov 06, 2009 at 06:42:21PM +0100, Falempe Jocelyn wrote: > > > In fact we are doing "retention" in idle and with the suspend path. It's > > specific to Android, with the global suspend and wakelock framework. > > When all wakelocks are released (ie screen is black, no running app), > > the phone goes to suspend, which freeze userspace and also suspend the > > device driver. This way you can choose the wakeup sources, and stay in > > suspend during a long time (a few hours). Without this, you have to > > track down all user space app that wakeup the phone, and it is hard to > > sleep more than a few second. > > What's triggering the application wakeups? If it's just timeouts, can't > you simply adjust the range timer slop so that the timeouts don't fire? yes that's a good point. I think google chose the suspend way also because it synchronize filesystem, and some driver can enter deeper sleep, knowing that the user won't notice the increased latency. it protects also the phone against a crashed/bad app that would eat 100% cpu always. > > > The drawback is that when you want to wakeup, it takes a lot of time to > > unfreeze the userspace, and resume all the device driver. This is what > > this feature address (for low-level wakeup only). > > But as this patch is not Android specific, I think other platforms may > > use it too. > > Yeah, I can certainly see the appeal if you have that constraint. > -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Patch
diff --git a/include/linux/quickwakeup.h b/include/linux/quickwakeup.h new file mode 100755 index 0000000..60df3b8 --- /dev/null +++ b/include/linux/quickwakeup.h @@ -0,0 +1,33 @@ +/* include/linux/quickwakeup.h + * + * Copyright (C) 2009 Motorola. + * + * 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. + * + */ + +struct quickwakeup_ops { + struct list_head list; + int (*qw_callback) (void); + int (*qw_check)(void); + int checked; +}; + +#ifdef CONFIG_QUICK_WAKEUP + +int quickwakeup_register(struct quickwakeup_ops *ops); +int quickwakeup_check(void); +int quickwakeup_execute(void); +void quickwakeup_unregister(struct quickwakeup_ops *ops); + +#else +static int quickwakeup_register(struct quickwakeup_ops *ops) { return 0; }; +void quickwakeup_unregister(struct quickwakeup_ops *ops) {}; +#endif diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 39263f4..5671f98 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -236,3 +236,11 @@ config PM_RUNTIME and the bus type drivers of the buses the devices are on are responsible for the actual handling of the autosuspend requests and wake-up events. + +config QUICK_WAKEUP + bool "Quick wakeup" + depends on SUSPEND + default n + ---help--- + Allow kernel driver to do periodic jobs without resuming the full system + This option can increase battery life on android powered smartphone. diff --git a/kernel/power/Makefile b/kernel/power/Makefile index 4319181..18b55e5 100644 --- a/kernel/power/Makefile +++ b/kernel/power/Makefile @@ -10,5 +10,5 @@ obj-$(CONFIG_SUSPEND) += 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 - +obj-$(CONFIG_QUICK_WAKEUP) += quickwakeup.o obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o diff --git a/kernel/power/quickwakeup.c b/kernel/power/quickwakeup.c new file mode 100644 index 0000000..3ad7392 --- /dev/null +++ b/kernel/power/quickwakeup.c @@ -0,0 +1,60 @@ +/* kernel/power/quickwakeup.c + * + * Copyright (C) 2009 Motorola. + * + * 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/slab.h> +#include <linux/quickwakeup.h> + +static LIST_HEAD(qw_head); + +int quickwakeup_register(struct quickwakeup_ops *ops) +{ + list_add(&ops->list, &qw_head); + return 0; +} + +void quickwakeup_unregister(struct quickwakeup_ops *ops) +{ + list_del(&ops->list); +} + +int quickwakeup_check(void) +{ + int ret = 0; + struct quickwakeup_ops *index; + + list_for_each_entry(index, &qw_head, list) { + index->checked = index->qw_check(); + ret |= index->checked; + } + return ret; +} + +int quickwakeup_execute(void) +{ + int ret; + int count = 0; + struct quickwakeup_ops *index; + + list_for_each_entry(index, &qw_head, list) { + if (index->checked) + ret = index->qw_callback(); + if (ret != 0) + return ret; + count++; + } + if (!count) + return -1; + return 0; +} diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 6f10dfc..3fe1ec0 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -116,6 +116,28 @@ void __attribute__ ((weak)) arch_suspend_enable_irqs(void) local_irq_enable(); } +static int _suspend_enter(suspend_state_t state) +{ + int error; + arch_suspend_disable_irqs(); + BUG_ON(!irqs_disabled()); + + error = sysdev_suspend(PMSG_SUSPEND); + if (!error) { + if (!suspend_test(TEST_CORE)) + error = suspend_ops->enter(state); + sysdev_resume(); + } + if (!error) { +#ifdef CONFIG_QUICK_WAKEUP + quickwakeup_check(); +#endif + } + arch_suspend_enable_irqs(); + BUG_ON(irqs_disabled()); + return error; +} + /** * suspend_enter - enter the desired system sleep state. * @state: state to enter @@ -151,18 +173,14 @@ static int suspend_enter(suspend_state_t state) if (error || suspend_test(TEST_CPUS)) goto Enable_cpus; - arch_suspend_disable_irqs(); - BUG_ON(!irqs_disabled()); - - error = sysdev_suspend(PMSG_SUSPEND); - if (!error) { - if (!suspend_test(TEST_CORE)) - error = suspend_ops->enter(state); - sysdev_resume(); - } - - arch_suspend_enable_irqs(); - BUG_ON(irqs_disabled()); + error = _suspend_enter(state); +#ifdef CONFIG_QUICK_WAKEUP + while (!error && !quickwakeup_execute()) { + if (has_wake_lock(WAKE_LOCK_SUSPEND)) + break; + error = _suspend_enter(state); + } +#endif Enable_cpus: enable_nonboot_cpus();