msm: pm: Adjust for events with hard wakeups
Get the next event and setup a new timer to expire
earlier than the next event after accounting for the
latency of the low power state being entered. This
will ensure that the core is active to handle the event
when it arrives.
(cherry picked from commit dc318fd0c3d04f7af9720af50c0eb0c6ed2653e9)
Signed-off-by: Girish Mahadevan <girishm@codeaurora.org>
Change-Id: I6609a886df227c68ce78e270ef7d235e07725d44
Signed-off-by: Neha Pandey <nehap@codeaurora.org>
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 3b8f48d..6fb4901 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -49,6 +49,7 @@
#include "spm.h"
#include "timer.h"
#include "pm-boot.h"
+#include <mach/event_timer.h>
/******************************************************************************
* Debug Definitions
@@ -113,6 +114,7 @@
"standalone_power_collapse",
};
+static struct hrtimer pm_hrtimer;
static struct msm_pm_sleep_ops pm_sleep_ops;
/*
* Write out the attribute.
@@ -651,6 +653,28 @@
return time;
}
+/**
+ * pm_hrtimer_cb() : Callback function for hrtimer created if the
+ * core needs to be awake to handle an event.
+ * @hrtimer : Pointer to hrtimer
+ */
+static enum hrtimer_restart pm_hrtimer_cb(struct hrtimer *hrtimer)
+{
+ return HRTIMER_NORESTART;
+}
+
+/**
+ * msm_pm_set_timer() : Set an hrtimer to wakeup the core in time
+ * to handle an event.
+ */
+static void msm_pm_set_timer(uint32_t modified_time_us)
+{
+ u64 modified_time_ns = modified_time_us * NSEC_PER_USEC;
+ ktime_t modified_ktime = ns_to_ktime(modified_time_ns);
+ pm_hrtimer.function = pm_hrtimer_cb;
+ hrtimer_start(&pm_hrtimer, modified_ktime, HRTIMER_MODE_ABS);
+}
+
/******************************************************************************
* External Idle/Suspend Functions
*****************************************************************************/
@@ -663,15 +687,25 @@
int msm_pm_idle_prepare(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
- uint32_t latency_us;
- uint32_t sleep_us;
int i;
unsigned int power_usage = -1;
int ret = 0;
+ uint32_t modified_time_us = 0;
+ struct msm_pm_time_params time_param;
- latency_us = (uint32_t) pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
- sleep_us = (uint32_t) ktime_to_ns(tick_nohz_get_sleep_length());
- sleep_us = DIV_ROUND_UP(sleep_us, 1000);
+ time_param.latency_us =
+ (uint32_t) pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
+ time_param.sleep_us =
+ (uint32_t) (ktime_to_us(tick_nohz_get_sleep_length())
+ & UINT_MAX);
+ time_param.modified_time_us = 0;
+
+ if (!dev->cpu)
+ time_param.next_event_us =
+ (uint32_t) (ktime_to_us(get_next_event_time())
+ & UINT_MAX);
+ else
+ time_param.next_event_us = 0;
for (i = 0; i < dev->state_count; i++) {
struct cpuidle_state *state = &drv->states[i];
@@ -721,17 +755,18 @@
case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
if (!allow)
break;
+ /* fall through */
if (pm_sleep_ops.lowest_limits)
rs_limits = pm_sleep_ops.lowest_limits(true,
- mode, latency_us, sleep_us,
- &power);
+ mode, &time_param, &power);
if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
pr_info("CPU%u: %s: %s, latency %uus, "
"sleep %uus, limit %p\n",
dev->cpu, __func__, state->desc,
- latency_us, sleep_us, rs_limits);
+ time_param.latency_us,
+ time_param.sleep_us, rs_limits);
if (!rs_limits)
allow = false;
@@ -749,6 +784,7 @@
if (allow) {
if (power < power_usage) {
power_usage = power;
+ modified_time_us = time_param.modified_time_us;
ret = mode;
}
@@ -757,6 +793,8 @@
}
}
+ if (modified_time_us && !dev->cpu)
+ msm_pm_set_timer(modified_time_us);
return ret;
}
@@ -869,6 +907,11 @@
int i;
int64_t period = 0;
int64_t time = msm_pm_timer_enter_suspend(&period);
+ struct msm_pm_time_params time_param;
+
+ time_param.latency_us = -1;
+ time_param.sleep_us = -1;
+ time_param.next_event_us = 0;
if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
pr_info("%s\n", __func__);
@@ -906,8 +949,7 @@
#endif /* CONFIG_MSM_SLEEP_TIME_OVERRIDE */
if (pm_sleep_ops.lowest_limits)
rs_limits = pm_sleep_ops.lowest_limits(false,
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE, -1,
- -1, &power);
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE, &time_param, &power);
if (rs_limits) {
if (pm_sleep_ops.enter_sleep)
@@ -1024,6 +1066,7 @@
suspend_set_ops(&msm_pm_ops);
msm_pm_qtimer_available();
+ hrtimer_init(&pm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
msm_cpuidle_init();
return 0;