aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2012-05-16 15:55:54 +0100
committerNicolas Pitre <nicolas.pitre@linaro.org>2013-05-13 15:06:39 -0400
commit5b317d7415cb03c429551e18d777cfc843c43865 (patch)
tree031efb9434fa430489b499650b34abfe86b8aa88
parent150dbebaaed5e501a0676017d5a0b6f272f5d45f (diff)
ARM: bL_switcher: add clockevent save/restore support
Per-CPU timers that are shutdown when a CPU is switched over must be disabled upon switching and reprogrammed on the inbound CPU by relying on the clock events management API. save/restore sequence is executed with irqs disabled as mandated by the clock events API. The next_event is an absolute time, hence, when the inbound CPU resumes, if the timer has expired the min delta is forced into the tick device to fire after few cycles. This patch adds switching support for clock events that are per-CPU and have to be migrated when a switch takes place; the cpumask of the clock event device is checked against the cpumask of the current cpu, and if they match, the clockevent device mode is saved and it is put in shutdown mode. Resume code reprogrammes the tick device accordingly. Tested on A15/A7 fast models and architected timers. Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Signed-off-by: Nicolas Pitre <nico@linaro.org>
-rw-r--r--arch/arm/common/bL_switcher.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/arch/arm/common/bL_switcher.c b/arch/arm/common/bL_switcher.c
index 51685c8bbdb..dcba186ed2d 100644
--- a/arch/arm/common/bL_switcher.c
+++ b/arch/arm/common/bL_switcher.c
@@ -15,7 +15,11 @@
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/cpu_pm.h>
+#include <linux/cpumask.h>
#include <linux/workqueue.h>
+#include <linux/clockchips.h>
+#include <linux/hrtimer.h>
+#include <linux/tick.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/irqchip/arm-gic.h>
@@ -122,6 +126,8 @@ static int bL_switchpoint(unsigned long _arg)
static int bL_switch_to(unsigned int new_cluster_id)
{
unsigned int mpidr, cpuid, clusterid, ob_cluster, ib_cluster, this_cpu;
+ struct tick_device *tdev;
+ enum clock_event_mode tdev_mode;
int ret;
mpidr = read_mpidr();
@@ -167,6 +173,14 @@ static int bL_switch_to(unsigned int new_cluster_id)
*/
arch_send_wakeup_ipi_mask(cpumask_of(this_cpu));
+ tdev = tick_get_device(this_cpu);
+ if (tdev && !cpumask_equal(tdev->evtdev->cpumask, cpumask_of(this_cpu)))
+ tdev = NULL;
+ if (tdev) {
+ tdev_mode = tdev->evtdev->mode;
+ clockevents_set_mode(tdev->evtdev, CLOCK_EVT_MODE_SHUTDOWN);
+ }
+
ret = cpu_pm_enter();
/* we can not tolerate errors at this point */
@@ -198,6 +212,12 @@ static int bL_switch_to(unsigned int new_cluster_id)
ret = cpu_pm_exit();
+ if (tdev) {
+ clockevents_set_mode(tdev->evtdev, tdev_mode);
+ clockevents_program_event(tdev->evtdev,
+ tdev->evtdev->next_event, 1);
+ }
+
local_fiq_enable();
local_irq_enable();