--- linux-2.6.14-rc1-vatsa/include/linux/dyn-tick.h | 84 +++++++++++ linux-2.6.14-rc1-vatsa/kernel/dyn-tick.c | 182 ++++++++++++++++++++++++ 2 files changed, 266 insertions(+) diff -puN /dev/null kernel/dyn-tick.c --- /dev/null 2003-01-30 15:54:37.000000000 +0530 +++ linux-2.6.14-rc1-vatsa/kernel/dyn-tick.c 2005-09-22 23:58:51.000000000 +0530 @@ -0,0 +1,182 @@ +/* + * linux/kernel/dyn-tick.c + * + * Beginnings of generic dynamic tick timer support + * + * Copyright (C) 2004 Nokia Corporation + * Written by Tony Lindgen and + * Tuukka Tikkanen + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DYN_TICK_VERSION "050610-1" + +struct dyn_tick_state *dyn_tick; + +/* + * Arch independent code needed to reprogram next timer interrupt. + * Gets called, with IRQs disabled, from cpu_idle() before entering idle loop. + */ +unsigned int dyn_tick_reprogram_timer(void) +{ + int cpu = smp_processor_id(); + unsigned int delta; + + if (!dyn_tick_enabled()) + return 0; + + /* This is defined in asm/dyn-tick.h */ + dyn_tick_lock(); + + /* Check if we can start skipping ticks */ + write_seqlock(&xtime_lock); + + + cpu_set(cpu, nohz_cpu_mask); + + smp_wmb(); + + if (rcu_pending(cpu) || local_softirq_pending()) { + cpu_clear(cpu, nohz_cpu_mask); + return 0; + } + + delta = next_timer_interrupt() - jiffies; + + if (delta < dyn_tick->min_skip) { + cpu_clear(cpu, nohz_cpu_mask); + return 0; + } + + if (delta > dyn_tick->max_skip) + delta = dyn_tick->max_skip; + + dyn_tick->reprogram(delta); + + write_sequnlock(&xtime_lock); + + dyn_tick_unlock(); + + return delta; +} + +int dyn_tick_enable(void) +{ + unsigned long flags; + int ret = -ENODEV; + + if (dyn_tick) { + write_seqlock_irqsave(&xtime_lock, flags); + ret = 0; + if (!dyn_tick_enabled()) + ret = dyn_tick->enable(); + + if (ret == 0) + dyn_tick->state |= DYN_TICK_ENABLED; + } + write_sequnlock_irqrestore(&xtime_lock, flags); + } + + return ret; +} + +int dyn_tick_disable(void) +{ + unsigned long flags; + int ret = -ENODEV; + + if (dyn_tick) { + write_seqlock_irqsave(&xtime_lock, flags); + ret = 0; + if (dyn_tick_enabled()) + ret = dyn_tick->disable(); + + if (ret == 0) + dyn_tick->state &= ~DYN_TICK_ENABLED; + } + write_sequnlock_irqrestore(&xtime_lock, flags); + } + + return ret; +} + + +void dyn_tick_register(struct dyn_tick_timer *arch_timer) +{ + dyn_tick = arch_timer; + printk(KERN_INFO "dyn-tick: Registering dynamic tick timer v%s\n", + DYN_TICK_VERSION); +} + +/* + * --------------------------------------------------------------------------- + * Sysfs interface + * --------------------------------------------------------------------------- + */ + +extern struct sys_device device_timer; + +static ssize_t show_dyn_tick_enable(struct sys_device *dev, char *buf) +{ + return sprintf(buf, "enabled:\t%i\n", dyn_tick_enabled()); +} + +static ssize_t set_dyn_tick_enable(struct sys_device *dev, const char *buf, + size_t count) +{ + unsigned long flags; + unsigned int enable = simple_strtoul(buf, NULL, 2); + + if (enable) + dyn_tick_enable(); + else + dyn_tick_disable(); + + return count; +} + +static SYSDEV_ATTR(enable, 0644, show_dyn_tick_enable, + set_dyn_tick_enable); + +static struct sysdev_class dyn_tick_sysclass = { + set_kset_name("dyn_tick"), +}; + +static struct sys_device device_dyn_tick = { + .id = 0, + .cls = &dyn_tick_sysclass, +}; + +static int init_dyn_tick_sysfs(void) +{ + int error = 0; + + if (!dyn_tick) + goto out; + + if ((error = sysdev_class_register(&dyn_tick_sysclass))) + goto out; + if ((error = sysdev_register(&device_dyn_tick))) + goto out; + error = sysdev_create_file(&device_dyn_tick, &attr_enable); + +out: + return error; +} + +late_initcall(init_dyn_tick_sysfs); diff -puN /dev/null include/linux/dyn-tick.h --- /dev/null 2003-01-30 15:54:37.000000000 +0530 +++ linux-2.6.14-rc1-vatsa/include/linux/dyn-tick.h 2005-09-22 23:59:46.000000000 +0530 @@ -0,0 +1,84 @@ +/* + * linux/include/linux/dyn-tick.h + * + * Copyright (C) 2004 Nokia Corporation + * Written by Tony Lindgen and + * Tuukka Tikkanen + * + * 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. + */ + +#ifndef _DYN_TICK_TIMER_H +#define _DYN_TICK_TIMER_H + +#include +#include + +#define DYN_TICK_ENABLED (1 << 1) + +/* + * Abstraction of a dynamic tick source: + * + * @state : current state (bitfield) + * @max_skip : maximum number of ticks to skip + * @min_skip : minimum number of ticks to skip + * @enable_dyn_tick : called via sysfs to enable interrupt skipping + * @disable_dyn_tick : called via sysfs to disable interrupt skipping + * @reprogram : reprogram the interrupt source to skip ticks. + Passed with one argument - the number of ticks + to skip. Called with IRQs disabled and with + write_xtime_lock held. + * @recover_time : handler to recover time. Called when coming out of + tickless state by each CPU. + * @enter_all_cpus_idle : last cpu to go idle can call this. Typically + invoked from reprogram routine. + * @exit_all_cpus_idle : called when coming out of all_cpus_idle state + * @lock : Used to serialize enter/exit routines + * with modifications to nohz_cpu_mask. + */ + +struct dyn_tick_timer { + unsigned int state; + unsigned long max_skip; + unsigned long min_skip; + void (*enable) (void); + void (*disable) (void); + unsigned long (*reprogram) (unsigned long); + unsigned long (*recover_time) (int, void *, struct pt_regs *); + void (*enter_all_cpus_idle) (int); + void (*exit_all_cpus_idle) (int); + spinlock_t lock; +}; + +extern struct dyn_tick_timer *dyn_tick; + +extern void dyn_tick_timer_register(struct dyn_tick_timer *new_dyntick_timer); +extern int dyn_tick_enable(void); +extern int dyn_tick_disable(void); + +#ifdef CONFIG_NO_IDLE_HZ +extern unsigned int dyn_tick_reprogram_timer(void); + +static inline int dyn_tick_enabled(void) +{ + return (dyn_tick->state & DYN_TICK_ENABLED); +} + +#else /* CONFIG_NO_IDLE_HZ */ +static inline unsigned int dyn_tick_reprogram_timer(void) +{ + return 0; +} + +static inline int dyn_tick_enabled(void) +{ + return 0; +} +#endif /* CONFIG_NO_IDLE_HZ */ + +/* Pick up arch specific header */ +#include + +#endif /* _DYN_TICK_TIMER_H */ _