]> pilppa.com Git - linux-2.6-omap-h63xx.git/commitdiff
ARM: Add support for dynamic tick timer
authorTony Lindgren <tony@atomide.com>
Mon, 9 May 2005 20:05:34 +0000 (13:05 -0700)
committerTony Lindgren <tony@atomide.com>
Mon, 9 May 2005 20:05:34 +0000 (13:05 -0700)
Adds ARM generic support for dynamic tick timer.

Signed-off-by: Tony Lindgren <tony@atomide.com>
arch/arm/kernel/irq.c
arch/arm/kernel/time.c
include/asm-arm/mach/time.h
include/linux/signal.h

index ff187f4308f01ec786056f07b82299d8adf90cb2..32a144e361e69d4af1300f5331ab4ef1513a3ce6 100644 (file)
@@ -4,6 +4,10 @@
  *  Copyright (C) 1992 Linus Torvalds
  *  Modifications for ARM processor Copyright (C) 1995-2000 Russell King.
  *
+ *  Support for Dynamic Tick Timer Copyright (C) 2004-2005 Nokia Corporation.
+ *  Dynamic Tick Timer written by Tony Lindgren <tony@atomide.com> and
+ *  Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>.
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -37,6 +41,7 @@
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/mach/irq.h>
+#include <asm/mach/time.h>
 
 /*
  * Maximum IRQ count.  Currently, this is arbitary.  However, it should
@@ -332,6 +337,12 @@ __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs)
        if (!(action->flags & SA_INTERRUPT))
                local_irq_enable();
 
+#ifdef CONFIG_NO_IDLE_HZ
+       if ((!(action->flags & SA_TIMER)) && system_timer->dyn_tick->handler &&
+           (system_timer->dyn_tick->state & DYN_TICK_ENABLED))
+               system_timer->dyn_tick->handler(irq, 0, regs);
+#endif
+
        status = 0;
        do {
                ret = action->handler(irq, action->dev_id, regs);
index c232f24f4a60042806958f8e74e685af473e3196..d0d4fed333eb2b82974c4cba9f9afe736e6b6c98 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/profile.h>
 #include <linux/sysdev.h>
 #include <linux/timer.h>
+#include <linux/pm.h>
 
 #include <asm/hardware.h>
 #include <asm/io.h>
@@ -350,6 +351,49 @@ void timer_tick(struct pt_regs *regs)
 #endif
 }
 
+#ifdef CONFIG_NO_IDLE_HZ
+int timer_dyn_tick_enable(void)
+{
+       unsigned long flags;
+       int ret = -ENODEV;
+
+       write_seqlock_irqsave(&xtime_lock, flags);
+       if (!system_timer->dyn_tick || !system_timer->dyn_tick->enable)
+               goto out_err;
+
+       ret = system_timer->dyn_tick->enable();
+       if (ret != 0)
+               goto out_err;
+
+       if (system_timer->dyn_tick->handler)
+               system_timer->dyn_tick->state |= DYN_TICK_ENABLED;
+
+       write_sequnlock_irqrestore(&xtime_lock, flags);
+
+       return ret;
+
+out_err:
+       system_timer->dyn_tick->state &= ~DYN_TICK_ENABLED;
+       write_sequnlock_irqrestore(&xtime_lock, flags);
+       return ret;
+}
+
+int timer_dyn_tick_disable(void)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       write_seqlock_irqsave(&xtime_lock, flags);
+       if (system_timer->dyn_tick && system_timer->dyn_tick->disable)
+               ret = system_timer->dyn_tick->disable();
+
+       system_timer->dyn_tick->state &= ~DYN_TICK_ENABLED;
+       write_sequnlock_irqrestore(&xtime_lock, flags);
+
+       return ret;
+}
+#endif
+
 #ifdef CONFIG_PM
 static int timer_suspend(struct sys_device *dev, pm_message_t state)
 {
@@ -381,6 +425,29 @@ static struct sysdev_class timer_sysclass = {
        .resume         = timer_resume,
 };
 
+#ifdef CONFIG_NO_IDLE_HZ
+static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
+{
+       return sprintf(buf, "%i\n",
+                      (system_timer->dyn_tick->state & DYN_TICK_ENABLED) >> 1);
+}
+
+static ssize_t timer_set_dyn_tick(struct sys_device *dev, const char *buf,
+                                 size_t count)
+{
+       int ret = 0;
+       unsigned int enable = simple_strtoul(buf, NULL, 2);
+
+       if (enable)
+               ret = timer_dyn_tick_enable();
+       else
+               ret = timer_dyn_tick_disable();
+
+       return count;
+}
+static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick);
+#endif
+
 static int __init timer_init_sysfs(void)
 {
        int ret = sysdev_class_register(&timer_sysclass);
@@ -388,6 +455,15 @@ static int __init timer_init_sysfs(void)
                system_timer->dev.cls = &timer_sysclass;
                ret = sysdev_register(&system_timer->dev);
        }
+
+#ifdef CONFIG_NO_IDLE_HZ
+       ret = sysdev_create_file(&system_timer->dev, &attr_dyn_tick);
+#if defined(CONFIG_NO_IDLE_HZ_ENABLED)
+       /* Turn on dynamic tick after calibrate delay for correct bogomips */
+       ret = timer_dyn_tick_enable();
+#endif
+#endif
+
        return ret;
 }
 
index 5cf4fd659fd54d4b64e2c4dbd9faa1690da22f72..c46914855bc52dc403282c30187231ba6178ce3f 100644 (file)
@@ -39,7 +39,27 @@ struct sys_timer {
        void                    (*suspend)(void);
        void                    (*resume)(void);
        unsigned long           (*offset)(void);
+
+#ifdef CONFIG_NO_IDLE_HZ
+       struct dyn_tick_timer   *dyn_tick;
+#endif
+
+};
+
+#ifdef CONFIG_NO_IDLE_HZ
+
+#define DYN_TICK_SKIPPING      (1 << 2)
+#define DYN_TICK_ENABLED       (1 << 1)
+#define DYN_TICK_SUITABLE      (1 << 0)
+
+struct dyn_tick_timer {
+       unsigned int    state;                  /* Current state */
+       int             (*enable)(void);        /* Enables dynamic tick */
+       int             (*disable)(void);       /* Disables dynamic tick */
+       void            (*reprogram)(void);     /* Reprograms the timer */
+       int             (*handler)(int, void *, struct pt_regs *);
 };
+#endif
 
 extern struct sys_timer *system_timer;
 extern void timer_tick(struct pt_regs *);
index 0a98f5ec5caed28fdfcaa91c183e7ef181534833..4c877abdc3f8a4e7796c04eb7c9251f1bcd20d34 100644 (file)
  *
  * SA_INTERRUPT is also used by the irq handling routines.
  * SA_SHIRQ is for shared interrupt support on PCI and EISA.
+ * SA_TIMER is used by dynamic tick timer.
  */
 #define SA_PROBE               SA_ONESHOT
+#define SA_TIMER               SA_NOMASK
 #define SA_SAMPLE_RANDOM       SA_RESTART
 #define SA_SHIRQ               0x04000000