alarm: Adding new threshold to avoid intensive wakeup from S3
authorAymen Zayet <aymenx.zayet@intel.com>
Wed, 7 Mar 2012 13:19:03 +0000 (14:19 +0100)
committerbuildbot <buildbot@intel.com>
Tue, 5 Jun 2012 12:22:29 +0000 (05:22 -0700)
BZ: 26623

For Mobile Internet Devices, saving power is one of the main requirement.
In general, such devices supports already some power management machanism
that allows to to optimize the power consumption (such as suspend to
ram and hibernation). But using such mechanisms could be very penalizing
in term of power consumption in the case where the wakeup from deep sleep
is triggered periodically.

Actually the suspend process starts by waken up all the devices in order
to well prepare them for a deep sleep. Experimental results shows that,
depending on the devices presents on the system, the suspend increases
significantly the power if the wakeup capable alarms are configured to be
triggered before a certain threshold.

Be careful while setting this parameter: a wrong value may increase the
power consumption. So, if no full study was performed on the target
platform, please leave it at its default value.

Change-Id: I6ccc031f4f6991e762e74b8c92a7fa850347f0a5
Signed-off-by: Vishwesh M Rudramuni<vishwesh.m.rudramuni@intel.com>
Signed-off-by: Aymen Zayet <aymenx.zayet@intel.com>
Reviewed-on: http://android.intel.com:8080/51243
Reviewed-by: Martin, LoicX <loicx.martin@intel.com>
Tested-by: Martin, LoicX <loicx.martin@intel.com>
Reviewed-by: Gross, Mark <mark.gross@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
drivers/rtc/Kconfig
drivers/rtc/alarm.c
include/linux/rtc.h
kernel/power/wakelock.c

index 6552aec..959fd9f 100644 (file)
@@ -116,6 +116,29 @@ config RTC_INTF_ALARM
          Also provides an interface to set the wall time which must be used
          for elapsed realtime to work.
 
+config ALARM_PM_THRESHOLD
+       int "Wakeup Alarm Threshold for deep sleep (Experimental)"
+       range 0 3600
+       depends on RTC_INTF_ALARM_DEV && ANDROID && PM_SLEEP && PM_RUNTIME
+       default 0
+       help
+         For Mobile Internet Devices, saving power is one of the main requirement.
+         In general, such devices supports already some power management machanism
+         that allows to to optimize the power consumption (such as suspend to
+         ram and hibernation). But using such mechanisms could be very penalizing
+         in term of power consumption in the case where the wakeup from deep sleep
+         is triggered periodically.
+
+         Actually the suspend process starts by waken up all the devices in order
+         to well prepare them for a deep sleep. Experimental results shows that,
+         depending on the devices presents on the system, the suspend increases
+         significantly the power if the wakeup capable alarms are configured to be
+         triggered before a certain threshold.
+
+         Be careful while setting this parameter: a wrong value may increase the
+         power consumption. So, if no full study was performed on the target
+         platform, please leave it at its default value.
+
 config RTC_INTF_ALARM_DEV
        bool "Android alarm device"
        depends on RTC_INTF_ALARM
index 55cc50f..7f3de25 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/reboot.h>
 #include <linux/notifier.h>
 
-
 #define ANDROID_ALARM_PRINT_ERROR (1U << 0)
 #define ANDROID_ALARM_PRINT_INIT_STATUS (1U << 1)
 #define ANDROID_ALARM_PRINT_TSET (1U << 2)
@@ -69,6 +68,7 @@ static struct wake_lock alarm_rtc_wake_lock;
 static struct platform_device *alarm_platform_dev;
 struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT];
 static bool suspended;
+static u32 config_pm_threshold = (u32)CONFIG_ALARM_PM_THRESHOLD;
 
 static int alarm_reboot_callback(struct notifier_block *nfb,
                                 unsigned long event, void *data);
@@ -427,6 +427,28 @@ static void alarm_triggered_func(void *p)
        wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
 }
 
+static struct alarm_queue *alarm_find_next_wakeup_hrtimer(void)
+{
+       struct alarm_queue *wakeup_queue = NULL;
+       struct alarm_queue *tmp_queue = NULL;
+
+       tmp_queue = &alarms[ANDROID_ALARM_RTC_WAKEUP];
+       if (tmp_queue->first)
+               wakeup_queue = tmp_queue;
+       tmp_queue = &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
+       if (tmp_queue->first && (!wakeup_queue ||
+                               hrtimer_get_expires(&tmp_queue->timer).tv64 <
+                               hrtimer_get_expires(&wakeup_queue->timer).tv64))
+               wakeup_queue = tmp_queue;
+       tmp_queue = &alarms[ANDROID_ALARM_POWER_OFF_WAKEUP];
+       if (tmp_queue->first && (!wakeup_queue ||
+                               hrtimer_get_expires(&tmp_queue->timer).tv64 <
+                               hrtimer_get_expires(&wakeup_queue->timer).tv64))
+               wakeup_queue = tmp_queue;
+
+       return wakeup_queue;
+}
+
 static int alarm_suspend(struct device *dev)
 {
        int                 err = 0;
@@ -438,7 +460,6 @@ static int alarm_suspend(struct device *dev)
        struct timespec     rtc_delta;
        struct timespec     wall_time;
        struct alarm_queue *wakeup_queue = NULL;
-       struct alarm_queue *tmp_queue = NULL;
 
        spin_lock_irqsave(&alarm_slock, flags);
        suspended = true;
@@ -449,19 +470,7 @@ static int alarm_suspend(struct device *dev)
                        ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].timer);
        hrtimer_cancel(&alarms[ANDROID_ALARM_POWER_OFF_WAKEUP].timer);
 
-       tmp_queue = &alarms[ANDROID_ALARM_RTC_WAKEUP];
-       if (tmp_queue->first)
-               wakeup_queue = tmp_queue;
-       tmp_queue = &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
-       if (tmp_queue->first && (!wakeup_queue ||
-                               hrtimer_get_expires(&tmp_queue->timer).tv64 <
-                               hrtimer_get_expires(&wakeup_queue->timer).tv64))
-               wakeup_queue = tmp_queue;
-       tmp_queue = &alarms[ANDROID_ALARM_POWER_OFF_WAKEUP];
-       if (tmp_queue->first && (!wakeup_queue ||
-                               hrtimer_get_expires(&tmp_queue->timer).tv64 <
-                               hrtimer_get_expires(&wakeup_queue->timer).tv64))
-               wakeup_queue = tmp_queue;
+       wakeup_queue = alarm_find_next_wakeup_hrtimer();
        if (wakeup_queue) {
                rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
                getnstimeofday(&wall_time);
@@ -529,6 +538,31 @@ static int alarm_resume(struct device *dev)
        return 0;
 }
 
+int alarm_pm_wake_check(void)
+{
+       struct alarm_queue *wk_queue = alarm_find_next_wakeup_hrtimer();
+
+       if (wk_queue && config_pm_threshold) {
+               /*
+                * Compute the timestamp of the next wakeup alarm in
+                * second.
+                */
+               ktime_t expire = hrtimer_get_remaining(
+                       &wk_queue->timer);
+               struct timespec x = ktime_to_timespec(expire);
+               unsigned long timeout = timespec_to_jiffies(&x);
+               unsigned long next_alarm_secs = timeout / HZ;
+
+               if (next_alarm_secs < config_pm_threshold) {
+                       wake_lock_timeout(&alarm_rtc_wake_lock,
+                                         timeout + HZ);
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
 static struct rtc_task alarm_rtc_task = {
        .func = alarm_triggered_func
 };
@@ -657,7 +691,6 @@ static int __init alarm_driver_init(void)
                goto err2;
 
        register_reboot_notifier(&alarm_reboot_notifier_block);
-
        return 0;
 
 err2:
index 93f4d03..024c68e 100644 (file)
@@ -104,7 +104,7 @@ struct rtc_pll_info {
 
 #include <linux/types.h>
 #include <linux/interrupt.h>
-
+extern int alarm_pm_wake_check(void);
 extern int rtc_month_days(unsigned int month, unsigned int year);
 extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year);
 extern int rtc_valid_tm(struct rtc_time *tm);
index 678d0bf..c588935 100644 (file)
@@ -280,7 +280,7 @@ static void suspend(struct work_struct *work)
        int entry_event_num;
        struct timespec ts_entry, ts_exit;
 
-       if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
+       if (has_wake_lock(WAKE_LOCK_SUSPEND) || !alarm_pm_wake_check()) {
                if (debug_mask & DEBUG_SUSPEND)
                        pr_info("suspend: abort suspend\n");
                return;
@@ -289,6 +289,7 @@ static void suspend(struct work_struct *work)
        entry_event_num = current_event_num;
        if (debug_mask & DEBUG_SUSPEND)
                pr_info("suspend: enter suspend\n");
+
        getnstimeofday(&ts_entry);
        ret = pm_suspend(requested_suspend_state);
        getnstimeofday(&ts_exit);