Hi Tony I assume you're maintaining the dyn tick patches for i386 posted on the muru website as your email is listed there. I thought you might be interested in this patch for dyn-ticks which removes most of the #ifdefs out of common code paths as per linux kernel style and moves more code into dyn-tick.c. Most of it is straight forward code reorganisation, but to keep do_timer_interrupt inlined I'd have to move it's code around somewhat. That may be a better option but I've tried to fiddle with the mainline code as little as possible. Patch applies to 2.6.12 with patch-dynamic-tick-2.6.12-rc6-050610-1 applied cc'ed lkml just for public record of the patch. Cheers, Con
Move most of the dynamic ticks code that is #ifdef'd out of code paths and put it into dyn-tick.c Signed-off-by: Con Kolivas <[email protected]> arch/i386/kernel/Makefile | 2 arch/i386/kernel/apic.c | 36 ---------- arch/i386/kernel/dyn-tick.c | 146 ++++++++++++++++++++++++++++++++++++++++++++ arch/i386/kernel/irq.c | 5 - arch/i386/kernel/time.c | 72 --------------------- include/asm/dyn-tick.h | 4 - include/linux/dyn-tick.h | 12 +++ 7 files changed, 165 insertions(+), 112 deletions(-) Index: linux-2.6.12-dt/arch/i386/kernel/apic.c =================================================================== --- linux-2.6.12-dt.orig/arch/i386/kernel/apic.c 2005-07-29 01:43:15.000000000 +1000 +++ linux-2.6.12-dt/arch/i386/kernel/apic.c 2005-07-29 01:49:05.000000000 +1000 @@ -932,11 +932,8 @@ static void __setup_APIC_LVTT(unsigned i apic_timer_val = clocks/APIC_DIVISOR; -#ifdef CONFIG_NO_IDLE_HZ - /* Local APIC timer is 24-bit */ if (apic_timer_val) - dyn_tick->max_skip = 0xffffff / apic_timer_val; -#endif + set_dyn_tick_max_skip(apic_timer_val); apic_write_around(APIC_TMICT, apic_timer_val); } @@ -1051,12 +1048,7 @@ void __init setup_boot_APIC_clock(void) */ setup_APIC_timer(calibration_result); -#ifdef CONFIG_NO_IDLE_HZ - if (calibration_result) - dyn_tick->state |= DYN_TICK_USE_APIC; - else - printk(KERN_INFO "dyn-tick: Cannot use local APIC\n"); -#endif + setup_dyn_tick_use_apic(calibration_result); local_irq_enable(); } @@ -1086,18 +1078,6 @@ void enable_APIC_timer(void) } } -#if defined(CONFIG_NO_IDLE_HZ) -void reprogram_apic_timer(unsigned int count) -{ - unsigned long flags; - - count *= apic_timer_val; - local_irq_save(flags); - apic_write_around(APIC_TMICT, count); - local_irq_restore(flags); -} -#endif - /* * the frequency of the profiling timer can be changed * by writing a multiplier value into /proc/profile. @@ -1210,21 +1190,11 @@ fastcall void smp_apic_timer_interrupt(s */ irq_enter(); -#ifdef CONFIG_NO_IDLE_HZ /* * Check if we need to wake up PIT interrupt handler. * Otherwise just wake up local APIC timer. */ - do { - seq = read_seqbegin(&xtime_lock); - if (dyn_tick->state & (DYN_TICK_ENABLED | DYN_TICK_SKIPPING)) { - if (dyn_tick->skip_cpu == cpu && dyn_tick->skip > DYN_TICK_MIN_SKIP) - dyn_tick->interrupt(99, NULL, regs); - else - reprogram_apic_timer(1); - } - } while (read_seqretry(&xtime_lock, seq)); -#endif + wakeup_pit_or_apic(seq, cpu, ®s); smp_local_timer_interrupt(regs); irq_exit(); Index: linux-2.6.12-dt/arch/i386/kernel/dyn-tick.c =================================================================== --- linux-2.6.12-dt.orig/arch/i386/kernel/dyn-tick.c 2005-07-29 01:43:15.000000000 +1000 +++ linux-2.6.12-dt/arch/i386/kernel/dyn-tick.c 2005-07-29 11:46:48.000000000 +1000 @@ -17,6 +17,7 @@ #include <linux/module.h> #include <linux/dyn-tick.h> +#ifdef CONFIG_NO_IDLE_HZ void arch_reprogram_timer(void) { if (cpu_has_local_apic()) { @@ -43,3 +44,148 @@ int __init dyn_tick_init(void) return 0; } arch_initcall(dyn_tick_init); + +static unsigned long long last_tick; + +/* + * This interrupt handler updates the time based on number of jiffies skipped + * It would be somewhat more optimized to have a customa handler in each timer + * using hardware ticks instead of nanoseconds. Note that CONFIG_NO_IDLE_HZ + * currently disables timer fallback on skipped jiffies. + */ +irqreturn_t dyn_tick_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + volatile unsigned long long now; + unsigned int skipped = 0; + + write_seqlock_irqsave(&xtime_lock, flags); + now = cur_timer->monotonic_clock(); + while (now - last_tick >= NS_TICK_LEN) { + last_tick += NS_TICK_LEN; + cur_timer->mark_offset(); + do_timer_interrupt(irq, NULL, regs); + skipped++; + } + if (dyn_tick->state & (DYN_TICK_ENABLED | DYN_TICK_SKIPPING)) { + dyn_tick->skip = 1; + if (cpu_has_local_apic()) + reprogram_apic_timer(dyn_tick->skip); + reprogram_pit_timer(dyn_tick->skip); + dyn_tick->state |= DYN_TICK_ENABLED; + dyn_tick->state &= ~DYN_TICK_SKIPPING; + } + write_sequnlock_irqrestore(&xtime_lock, flags); + + return IRQ_HANDLED; +} + +int __init dyn_tick_arch_init(void) +{ + unsigned long flags; + + write_seqlock_irqsave(&xtime_lock, flags); + last_tick = cur_timer->monotonic_clock(); + dyn_tick->skip = 1; + if (!(dyn_tick->state & DYN_TICK_USE_APIC) || !cpu_has_local_apic()) + dyn_tick->max_skip = 0xffff/LATCH; /* PIT timer length */ + printk(KERN_INFO "dyn-tick: Maximum ticks to skip limited to %i\n", + dyn_tick->max_skip); + write_sequnlock_irqrestore(&xtime_lock, flags); + + dyn_tick->interrupt = dyn_tick_timer_interrupt; + replace_timer_interrupt(dyn_tick->interrupt); + + return 0; +} + +/* Reproduced functions below here */ +inline void set_dyn_tick_max_skip(u32 apic_timer_val) +{ + dyn_tick->max_skip = 0xffffff / apic_timer_val; +} + +inline void setup_dyn_tick_use_apic(unsigned int calibration_result) +{ + if (calibration_result) + dyn_tick->state |= DYN_TICK_USE_APIC; + else + printk(KERN_INFO "dyn-tick: Cannot use local APIC\n"); +} + +void wakeup_pit_or_apic(unsigned long seq, int cpu, struct pt_regs *regs) +{ + do { + seq = read_seqbegin(&xtime_lock); + if (dyn_tick->state & (DYN_TICK_ENABLED | DYN_TICK_SKIPPING)) { + if (dyn_tick->skip_cpu == cpu && dyn_tick->skip > DYN_TICK_MIN_SKIP) + dyn_tick->interrupt(99, NULL, regs); + else + reprogram_apic_timer(1); + } + } while (read_seqretry(&xtime_lock, seq)); +} + +void dyn_tick_interrupt(int irq, struct pt_regs *regs) +{ + if (dyn_tick->state & (DYN_TICK_ENABLED | DYN_TICK_SKIPPING) && irq != 0) + dyn_tick->interrupt(irq, NULL, regs); +} + +void dyn_tick_time_init(struct timer_opts *cur_timer) +{ + if (strncmp(cur_timer->name, "tsc", 3) == 0 || + strncmp(cur_timer->name, "pmtmr", 3) == 0) { + dyn_tick->state |= DYN_TICK_SUITABLE; + printk(KERN_INFO "dyn-tick: Found suitable timer: %s\n", + cur_timer->name); + } else + printk(KERN_ERR "dyn-tick: Cannot use timer %s\n", + cur_timer->name); +} + +#ifdef CONFIG_X86_LOCAL_APIC +void reprogram_apic_timer(unsigned int count) +{ + unsigned long flags; + + count *= apic_timer_val; + local_irq_save(flags); + apic_write_around(APIC_TMICT, count); + local_irq_restore(flags); +} +#else +void reprogram_apic_timer(unsigned int count) +{ +} + +#endif + +#else +inline void set_dyn_tick_max_skip(u32 apic_timer_val) +{ +} + +void reprogram_apic_timer(unsigned int count) +{ +} + +inline void setup_dyn_tick_use_apic(unsigned int calibration_result) +{ +} + +void wakeup_pit_or_apic(unsigned long seq, int cpu, struct pt_regs *regs) +{ +} + +void dyn_tick_interrupt(int irq, struct pt_regs *regs) +{ +} + +void dyn_tick_time_init(struct timer_opts *cur_timer) +{ +} + +#endif + + Index: linux-2.6.12-dt/arch/i386/kernel/irq.c =================================================================== --- linux-2.6.12-dt.orig/arch/i386/kernel/irq.c 2005-07-29 01:43:15.000000000 +1000 +++ linux-2.6.12-dt/arch/i386/kernel/irq.c 2005-07-29 02:03:33.000000000 +1000 @@ -74,10 +74,7 @@ fastcall unsigned int do_IRQ(struct pt_r } #endif -#ifdef CONFIG_NO_IDLE_HZ - if (dyn_tick->state & (DYN_TICK_ENABLED | DYN_TICK_SKIPPING) && irq != 0) - dyn_tick->interrupt(irq, NULL, regs); -#endif + dyn_tick_interrupt(irq, regs); #ifdef CONFIG_4KSTACKS Index: linux-2.6.12-dt/arch/i386/kernel/Makefile =================================================================== --- linux-2.6.12-dt.orig/arch/i386/kernel/Makefile 2005-07-29 00:06:26.000000000 +1000 +++ linux-2.6.12-dt/arch/i386/kernel/Makefile 2005-07-29 02:05:54.000000000 +1000 @@ -31,7 +31,7 @@ obj-$(CONFIG_MODULES) += module.o obj-y += sysenter.o vsyscall.o obj-$(CONFIG_ACPI_SRAT) += srat.o obj-$(CONFIG_HPET_TIMER) += time_hpet.o -obj-$(CONFIG_NO_IDLE_HZ) += dyn-tick.o +obj-y += dyn-tick.o obj-$(CONFIG_EFI) += efi.o efi_stub.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o Index: linux-2.6.12-dt/arch/i386/kernel/time.c =================================================================== --- linux-2.6.12-dt.orig/arch/i386/kernel/time.c 2005-07-29 01:43:15.000000000 +1000 +++ linux-2.6.12-dt/arch/i386/kernel/time.c 2005-07-29 11:53:52.000000000 +1000 @@ -248,7 +248,7 @@ EXPORT_SYMBOL(profile_pc); * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */ -static inline void do_timer_interrupt(int irq, void *dev_id, +void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { #ifdef CONFIG_X86_IO_APIC @@ -309,43 +309,6 @@ irqreturn_t timer_interrupt(int irq, voi return IRQ_HANDLED; } -#ifdef CONFIG_NO_IDLE_HZ -static unsigned long long last_tick; - -/* - * This interrupt handler updates the time based on number of jiffies skipped - * It would be somewhat more optimized to have a customa handler in each timer - * using hardware ticks instead of nanoseconds. Note that CONFIG_NO_IDLE_HZ - * currently disables timer fallback on skipped jiffies. - */ -irqreturn_t dyn_tick_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned long flags; - volatile unsigned long long now; - unsigned int skipped = 0; - - write_seqlock_irqsave(&xtime_lock, flags); - now = cur_timer->monotonic_clock(); - while (now - last_tick >= NS_TICK_LEN) { - last_tick += NS_TICK_LEN; - cur_timer->mark_offset(); - do_timer_interrupt(irq, NULL, regs); - skipped++; - } - if (dyn_tick->state & (DYN_TICK_ENABLED | DYN_TICK_SKIPPING)) { - dyn_tick->skip = 1; - if (cpu_has_local_apic()) - reprogram_apic_timer(dyn_tick->skip); - reprogram_pit_timer(dyn_tick->skip); - dyn_tick->state |= DYN_TICK_ENABLED; - dyn_tick->state &= ~DYN_TICK_SKIPPING; - } - write_sequnlock_irqrestore(&xtime_lock, flags); - - return IRQ_HANDLED; -} -#endif /* CONFIG_NO_IDLE_HZ */ - /* not static: needed by APM */ unsigned long get_cmos_time(void) { @@ -490,28 +453,6 @@ static void __init hpet_time_init(void) } #endif -#ifdef CONFIG_NO_IDLE_HZ - -int __init dyn_tick_arch_init(void) -{ - unsigned long flags; - - write_seqlock_irqsave(&xtime_lock, flags); - last_tick = cur_timer->monotonic_clock(); - dyn_tick->skip = 1; - if (!(dyn_tick->state & DYN_TICK_USE_APIC) || !cpu_has_local_apic()) - dyn_tick->max_skip = 0xffff/LATCH; /* PIT timer length */ - printk(KERN_INFO "dyn-tick: Maximum ticks to skip limited to %i\n", - dyn_tick->max_skip); - write_sequnlock_irqrestore(&xtime_lock, flags); - - dyn_tick->interrupt = dyn_tick_timer_interrupt; - replace_timer_interrupt(dyn_tick->interrupt); - - return 0; -} -#endif /* CONFIG_NO_IDLE_HZ */ - void __init time_init(void) { #ifdef CONFIG_HPET_TIMER @@ -532,16 +473,7 @@ void __init time_init(void) cur_timer = select_timer(); printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); -#ifdef CONFIG_NO_IDLE_HZ - if (strncmp(cur_timer->name, "tsc", 3) == 0 || - strncmp(cur_timer->name, "pmtmr", 3) == 0) { - dyn_tick->state |= DYN_TICK_SUITABLE; - printk(KERN_INFO "dyn-tick: Found suitable timer: %s\n", - cur_timer->name); - } else - printk(KERN_ERR "dyn-tick: Cannot use timer %s\n", - cur_timer->name); -#endif + dyn_tick_time_init(cur_timer); time_init_hook(); } Index: linux-2.6.12-dt/include/asm/dyn-tick.h =================================================================== --- linux-2.6.12-dt.orig/include/asm/dyn-tick.h 2005-07-29 01:43:15.000000000 +1000 +++ linux-2.6.12-dt/include/asm/dyn-tick.h 2005-07-29 01:58:54.000000000 +1000 @@ -19,11 +19,7 @@ extern void reprogram_pit_timer(int jiff extern void reprogram_apic_timer(unsigned int count); extern void replace_timer_interrupt(void * new_handler); -#if defined(CONFIG_NO_IDLE_HZ) && defined(CONFIG_X86_LOCAL_APIC) extern void reprogram_apic_timer(unsigned int count); -#else -#define reprogram_apic_timer(x) do {} while (0) -#endif #if defined(CONFIG_DYN_TICK_USE_APIC) && (defined(CONFIG_SMP) || defined(CONFIG_X86_UP_APIC)) #define cpu_has_local_apic() (dyn_tick->state & DYN_TICK_USE_APIC) Index: linux-2.6.12-dt/include/linux/dyn-tick.h =================================================================== --- linux-2.6.12-dt.orig/include/linux/dyn-tick.h 2005-07-29 01:43:15.000000000 +1000 +++ linux-2.6.12-dt/include/linux/dyn-tick.h 2005-07-29 11:41:48.000000000 +1000 @@ -14,6 +14,7 @@ #define _DYN_TICK_TIMER_H #include <linux/interrupt.h> +#include <asm/timer.h> #define DYN_TICK_TIMER_INT (1 << 4) #define DYN_TICK_USE_APIC (1 << 3) @@ -39,6 +40,14 @@ struct dyn_tick_timer { extern struct dyn_tick_state * dyn_tick; extern void dyn_tick_register(struct dyn_tick_timer * new_timer); +extern inline void set_dyn_tick_max_skip(u32 apic_timer_val); +extern void reprogram_apic_timer(unsigned int count); +extern inline void setup_dyn_tick_use_apic(unsigned int calibration_result); +extern void wakeup_pit_or_apic(unsigned long seq, int cpu, struct pt_regs *regs); +extern void dyn_tick_interrupt(int irq, struct pt_regs *regs); +extern void dyn_tick_time_init(struct timer_opts *cur_timer); +extern void do_timer_interrupt(int irq, void *dev_id, + struct pt_regs *regs); #define NS_TICK_LEN ((1 * 1000000000)/HZ) #define DYN_TICK_MIN_SKIP 2 @@ -47,6 +56,9 @@ extern void dyn_tick_register(struct dyn #ifdef CONFIG_NO_IDLE_HZ extern unsigned long dyn_tick_reprogram_timer(void); +extern irqreturn_t dyn_tick_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs); +extern int __init dyn_tick_arch_init(void); + #define dyn_tick_enabled() (dyn_tick->state & DYN_TICK_ENABLED) #else
Attachment:
pgpKuE7QbqNnF.pgp
Description: PGP signature
- Follow-Ups:
- Re: [PATCH] remove i386 dynamic ticks ifdefs
- From: Pavel Machek <[email protected]>
- Re: [PATCH] remove i386 dynamic ticks ifdefs
- Prev by Date: Time Flies (Twice as Fast)
- Next by Date: Re: [ALSA PATCH] 1.0.9b+
- Previous by thread: Time Flies (Twice as Fast)
- Next by thread: Re: [PATCH] remove i386 dynamic ticks ifdefs
- Index(es):