[ARM] 2864/1: VST aka CONFIG_NO_IDLE_HZ support for SA11x0
authorNicolas Pitre <nico@cam.org>
Thu, 1 Sep 2005 11:48:48 +0000 (12:48 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 1 Sep 2005 11:48:48 +0000 (12:48 +0100)
Patch from Nicolas Pitre

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/Kconfig
arch/arm/mach-sa1100/time.c

index dc0fafc7f9bd7ac5fb1dfb0078f502ebb5e1659c..68dfdba71d74126512efcd4996282ffce11b63a4 100644 (file)
@@ -365,8 +365,8 @@ config NO_IDLE_HZ
 
          Please note that dynamic tick may affect the accuracy of
          timekeeping on some platforms depending on the implementation.
-         Currently at least OMAP and PXA2xx platforms are known to have
-         accurate timekeeping with dynamic tick.
+         Currently at least OMAP, PXA2xx and SA11x0 platforms are known
+         to have accurate timekeeping with dynamic tick.
 
 config ARCH_DISCONTIGMEM_ENABLE
        bool
index a084b38698cfdc6243c4deb4f90e161689daf8bc..47e0420623fc25083a486f74887bff522260108b 100644 (file)
@@ -70,6 +70,11 @@ static unsigned long sa1100_gettimeoffset (void)
        return usec;
 }
 
+#ifdef CONFIG_NO_IDLE_HZ
+static unsigned long initial_match;
+static int match_posponed;
+#endif
+
 static irqreturn_t
 sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -77,6 +82,13 @@ sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
        write_seqlock(&xtime_lock);
 
+#ifdef CONFIG_NO_IDLE_HZ
+       if (match_posponed) {
+               match_posponed = 0;
+               OSMR0 = initial_match;
+       }
+#endif
+
        /*
         * Loop until we get ahead of the free running timer.
         * This ensures an exact clock tick count and time accuracy.
@@ -119,6 +131,42 @@ static void __init sa1100_timer_init(void)
        OSCR = 0;               /* initialize free-running timer, force first match */
 }
 
+#ifdef CONFIG_NO_IDLE_HZ
+static int sa1100_dyn_tick_enable_disable(void)
+{
+       /* nothing to do */
+       return 0;
+}
+
+static void sa1100_dyn_tick_reprogram(unsigned long ticks)
+{
+       if (ticks > 1) {
+               initial_match = OSMR0;
+               OSMR0 = initial_match + ticks * LATCH;
+               match_posponed = 1;
+       }
+}
+
+static irqreturn_t
+sa1100_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+       if (match_posponed) {
+               match_posponed = 0;
+               OSMR0 = initial_match;
+               if ((signed long)(initial_match - OSCR) <= 0)
+                       return sa1100_timer_interrupt(irq, dev_id, regs);
+       }
+       return IRQ_NONE;
+}
+
+static struct dyn_tick_timer sa1100_dyn_tick = {
+       .enable         = sa1100_dyn_tick_enable_disable,
+       .disable        = sa1100_dyn_tick_enable_disable,
+       .reprogram      = sa1100_dyn_tick_reprogram,
+       .handler        = sa1100_dyn_tick_handler,
+};
+#endif
+
 #ifdef CONFIG_PM
 unsigned long osmr[4], oier;
 
@@ -155,4 +203,7 @@ struct sys_timer sa1100_timer = {
        .suspend        = sa1100_timer_suspend,
        .resume         = sa1100_timer_resume,
        .offset         = sa1100_gettimeoffset,
+#ifdef CONFIG_NO_IDLE_HZ
+       .dyn_tick       = &sa1100_dyn_tick,
+#endif
 };