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.0 +1000
+++ linux-2.6.12-dt/arch/i386/kernel/apic.c 2005-07-29 01:49:05.0 +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 = 0xff / 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.0 +1000
+++ linux-2.6.12-dt/arch/i386/kernel/dyn-tick.c 2005-07-29 11:46:48.0 +1000
@@ -17,6 +17,7 @@
#include
#include
+#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