All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Dynamic tick for x86 version 050602-1
@ 2005-06-02  1:36 Tony Lindgren
  2005-06-02  1:54 ` Zwane Mwaikambo
                   ` (2 more replies)
  0 siblings, 3 replies; 32+ messages in thread
From: Tony Lindgren @ 2005-06-02  1:36 UTC (permalink / raw)
  To: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 525 bytes --]

Hi all,

Here's an updated version of the dynamic tick patch.

It's mostly clean-up and it's now using the standard
monotonic_clock() functions as suggested by John Stultz.

Please let me know of any issues with the patch. I'll continue to do
more clean-up on it, but I think the basic functionality is done.

Thomas, where do you have the latest version of your ACPI idle
patch? I'd like to add that to the dyn-tick page as well.

Older patches and some related links are at:

http://muru.com/linux/dyntick/

Regards,

Tony

[-- Attachment #2: patch-dynamic-tick-2.6.12-rc5-050602-1 --]
[-- Type: text/plain, Size: 26075 bytes --]

Index: linux-dev/arch/i386/Kconfig
===================================================================
--- linux-dev.orig/arch/i386/Kconfig	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/Kconfig	2005-06-01 17:54:32.000000000 -0700
@@ -458,6 +458,26 @@ config HPET_EMULATE_RTC
 	bool "Provide RTC interrupt"
 	depends on HPET_TIMER && RTC=y
 
+config NO_IDLE_HZ
+	bool "Dynamic Tick Timer - Skip timer ticks during idle"
+	help
+	  This option enables support for skipping timer ticks when the
+	  processor is idle. During system load, timer is continuous.
+	  This option saves power, as it allows the system to stay in
+	  idle mode longer. Currently supported timers are ACPI PM
+	  timer, local APIC timer, and TSC timer. HPET timer is currently
+	  not supported.
+
+config DYN_TICK_USE_APIC
+	bool "Use APIC timer instead of PIT timer"
+	help
+	  This option enables using APIC timer interrupt if your hardware
+	  supports it. APIC timer allows longer sleep periods compared
+	  to PIT timer. Note that on some hardware disabling PIT timer
+	  also disables APIC timer interrupts, and system won't run
+	  properly. Symptoms include slow system boot, and time running
+	  slow. If unsure, don't enable this option.
+
 config SMP
 	bool "Symmetric multi-processing support"
 	---help---
Index: linux-dev/arch/i386/kernel/Makefile
===================================================================
--- linux-dev.orig/arch/i386/kernel/Makefile	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/kernel/Makefile	2005-06-01 17:54:32.000000000 -0700
@@ -31,6 +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-$(CONFIG_EFI) 		+= efi.o efi_stub.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 
Index: linux-dev/arch/i386/kernel/apic.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/apic.c	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/kernel/apic.c	2005-06-01 17:54:32.000000000 -0700
@@ -26,6 +26,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/kernel_stat.h>
 #include <linux/sysdev.h>
+#include <linux/dyn-tick.h>
 
 #include <asm/atomic.h>
 #include <asm/smp.h>
@@ -909,6 +910,8 @@ void (*wait_timer_tick)(void) __initdata
 
 #define APIC_DIVISOR 16
 
+static u32 apic_timer_val;
+
 static void __setup_APIC_LVTT(unsigned int clocks)
 {
 	unsigned int lvtt_value, tmp_value, ver;
@@ -927,7 +930,15 @@ static void __setup_APIC_LVTT(unsigned i
 				& ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
 				| APIC_TDR_DIV_16);
 
-	apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR);
+	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
+
+	apic_write_around(APIC_TMICT, apic_timer_val);
 }
 
 static void __init setup_APIC_timer(unsigned int clocks)
@@ -1040,6 +1051,13 @@ 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
+
 	local_irq_enable();
 }
 
@@ -1068,6 +1086,18 @@ 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.
@@ -1160,6 +1190,7 @@ inline void smp_local_timer_interrupt(st
 
 fastcall void smp_apic_timer_interrupt(struct pt_regs *regs)
 {
+	unsigned long seq;
 	int cpu = smp_processor_id();
 
 	/*
@@ -1178,6 +1209,23 @@ fastcall void smp_apic_timer_interrupt(s
 	 * interrupt lock, which is the WrongThing (tm) to do.
 	 */
 	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
+
 	smp_local_timer_interrupt(regs);
 	irq_exit();
 }
Index: linux-dev/arch/i386/kernel/dyn-tick.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-dev/arch/i386/kernel/dyn-tick.c	2005-06-01 17:58:43.000000000 -0700
@@ -0,0 +1,45 @@
+/*
+ * linux/arch/i386/kernel/dyn-tick.c
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Tony Lindgen <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.
+ */
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/dyn-tick.h>
+
+void arch_reprogram_timer(void)
+{
+	if (cpu_has_local_apic()) {
+		disable_pit_timer();
+		if (dyn_tick->state & DYN_TICK_TIMER_INT)
+			reprogram_apic_timer(dyn_tick->skip);
+	} else {
+		if (dyn_tick->state & DYN_TICK_TIMER_INT)
+			reprogram_pit_timer(dyn_tick->skip);
+		else
+			disable_pit_timer();
+	}
+}
+
+static struct dyn_tick_timer arch_dyn_tick_timer = {
+	.arch_reprogram_timer	= &arch_reprogram_timer,
+};
+
+int __init dyn_tick_init(void)
+{
+	arch_dyn_tick_timer.arch_init = dyn_tick_arch_init;
+	dyn_tick_register(&arch_dyn_tick_timer);
+
+	return 0;
+}
+arch_initcall(dyn_tick_init);
Index: linux-dev/include/asm-i386/dyn-tick.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-dev/include/asm-i386/dyn-tick.h	2005-06-01 17:58:55.000000000 -0700
@@ -0,0 +1,37 @@
+/*
+ * linux/include/asm-i386/dyn-tick.h
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Tony Lindgen <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.
+ */
+
+extern int dyn_tick_arch_init(void);
+extern void disable_pit_timer(void);
+extern void reprogram_pit_timer(int jiffies_to_skip);
+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
+void reprogram_apic_timer(unsigned int count) {}
+#endif
+
+#undef DEBUG
+#ifdef DEBUG
+#define dbg_dyn_tick_irq() {if (skipped && skipped < dyn_tick->skip) \
+				printk("%u/%li ", skipped, dyn_tick->skip);}
+#else
+#define dbg_dyn_tick_irq() {}
+#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)
+#else
+#define cpu_has_local_apic()	0
+#endif
Index: linux-dev/arch/i386/kernel/irq.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/irq.c	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/kernel/irq.c	2005-06-01 17:54:32.000000000 -0700
@@ -15,6 +15,7 @@
 #include <linux/seq_file.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
+#include <linux/dyn-tick.h>
 
 DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_maxaligned_in_smp;
 EXPORT_PER_CPU_SYMBOL(irq_stat);
@@ -102,6 +103,12 @@ fastcall unsigned int do_IRQ(struct pt_r
 		);
 	} else
 #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
+
 		__do_IRQ(irq, regs);
 
 	irq_exit();
Index: linux-dev/arch/i386/kernel/process.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/process.c	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/kernel/process.c	2005-06-01 17:54:32.000000000 -0700
@@ -37,6 +37,7 @@
 #include <linux/kallsyms.h>
 #include <linux/ptrace.h>
 #include <linux/random.h>
+#include <linux/dyn-tick.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -160,6 +161,10 @@ void cpu_idle (void)
 			if (!idle)
 				idle = default_idle;
 
+#ifdef CONFIG_NO_IDLE_HZ
+			dyn_tick_reprogram_timer();
+#endif
+
 			__get_cpu_var(irq_stat).idle_timestamp = jiffies;
 			idle();
 		}
Index: linux-dev/arch/i386/kernel/time.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/time.c	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/kernel/time.c	2005-06-01 17:59:25.000000000 -0700
@@ -46,6 +46,7 @@
 #include <linux/bcd.h>
 #include <linux/efi.h>
 #include <linux/mca.h>
+#include <linux/dyn-tick.h>
 
 #include <asm/io.h>
 #include <asm/smp.h>
@@ -308,6 +309,51 @@ 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;
+
+	if (dyn_tick->state & DYN_TICK_DEBUG) {
+		if (irq == 0)
+			printk(".");
+		else
+			printk("%i ", irq);
+	}
+
+	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)) {
+		dbg_dyn_tick_irq();
+		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)
 {
@@ -416,7 +462,7 @@ static struct sysdev_class timer_sysclas
 
 
 /* XXX this driverfs stuff should probably go elsewhere later -john */
-static struct sys_device device_timer = {
+struct sys_device device_timer = {
 	.id	= 0,
 	.cls	= &timer_sysclass,
 };
@@ -452,6 +498,32 @@ 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 (!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);
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+	dyn_tick->state |= DYN_TICK_ENABLED;
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	return 0;
+}
+#endif	/* CONFIG_NO_IDLE_HZ */
+
 void __init time_init(void)
 {
 #ifdef CONFIG_HPET_TIMER
@@ -472,5 +544,16 @@ 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
+
 	time_init_hook();
 }
Index: linux-dev/arch/i386/kernel/timers/timer_pm.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/timers/timer_pm.c	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/kernel/timers/timer_pm.c	2005-06-01 17:54:32.000000000 -0700
@@ -168,6 +168,7 @@ static void mark_offset_pmtmr(void)
 	monotonic_base += delta * NSEC_PER_USEC;
 	write_sequnlock(&monotonic_lock);
 
+#ifndef CONFIG_NO_IDLE_HZ
 	/* convert to ticks */
 	delta += offset_delay;
 	lost = delta / (USEC_PER_SEC / HZ);
@@ -184,6 +185,7 @@ static void mark_offset_pmtmr(void)
 		first_run = 0;
 		offset_delay = 0;
 	}
+#endif
 }
 
 
Index: linux-dev/arch/i386/kernel/timers/timer_tsc.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/timers/timer_tsc.c	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/kernel/timers/timer_tsc.c	2005-06-01 17:54:32.000000000 -0700
@@ -348,6 +348,7 @@ static void mark_offset_tsc(void)
 
 	rdtsc(last_tsc_low, last_tsc_high);
 
+#ifndef CONFIG_NO_IDLE_HZ
 	spin_lock(&i8253_lock);
 	outb_p(0x00, PIT_MODE);     /* latch the count ASAP */
 
@@ -415,11 +416,14 @@ static void mark_offset_tsc(void)
 			cpufreq_delayed_get();
 	} else
 		lost_count = 0;
+#endif
+
 	/* update the monotonic base value */
 	this_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
 	monotonic_base += cycles_2_ns(this_offset - last_offset);
 	write_sequnlock(&monotonic_lock);
 
+#ifndef CONFIG_NO_IDLE_HZ
 	/* calculate delay_at_last_interrupt */
 	count = ((LATCH-1) - count) * TICK_SIZE;
 	delay_at_last_interrupt = (count + LATCH/2) / LATCH;
@@ -430,6 +434,7 @@ static void mark_offset_tsc(void)
 	 */
 	if (lost && abs(delay - delay_at_last_interrupt) > (900000/HZ))
 		jiffies_64++;
+#endif
 }
 
 static int __init init_tsc(char* override)
Index: linux-dev/arch/i386/mach-default/setup.c
===================================================================
--- linux-dev.orig/arch/i386/mach-default/setup.c	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/mach-default/setup.c	2005-06-01 17:54:32.000000000 -0700
@@ -85,6 +85,22 @@ void __init time_init_hook(void)
 	setup_irq(0, &irq0);
 }
 
+/**
+ * replace_timer_interrupt - allow replacing timer interrupt handler
+ *
+ * Description:
+ *	Can be used to replace timer interrupt handler with a more optimized
+ *	handler. Used for enabling and disabling of CONFIG_NO_IDLE_HZ.
+ */
+void replace_timer_interrupt(void * new_handler)
+{
+	unsigned long flags;
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+	irq0.handler = new_handler;
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+}
+
 #ifdef CONFIG_MCA
 /**
  * mca_nmi_hook - hook into MCA specific NMI chain
Index: linux-dev/include/linux/dyn-tick.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-dev/include/linux/dyn-tick.h	2005-06-01 17:54:33.000000000 -0700
@@ -0,0 +1,62 @@
+/*
+ * linux/include/linux/dyn-tick.h
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Tony Lindgen <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.
+ */
+
+#ifndef _DYN_TICK_TIMER_H
+#define _DYN_TICK_TIMER_H
+
+#include <linux/interrupt.h>
+
+#define DYN_TICK_DEBUG		(1 << 31)
+#define DYN_TICK_TIMER_INT	(1 << 4)
+#define DYN_TICK_USE_APIC	(1 << 3)
+#define DYN_TICK_SKIPPING	(1 << 2)
+#define DYN_TICK_ENABLED	(1 << 1)
+#define DYN_TICK_SUITABLE	(1 << 0)
+
+struct dyn_tick_state {
+	unsigned int state;		/* Current state */
+	int skip_cpu;			/* Skip handling processor */
+	unsigned long skip;		/* Ticks to skip */
+	unsigned int max_skip;		/* Max number of ticks to skip */
+	unsigned long irq_skip_mask;	/* Do not update time from these irqs */
+	irqreturn_t (*interrupt)(int, void *, struct pt_regs *);
+};
+
+struct dyn_tick_timer {
+	int (*arch_init) (void);
+	void (*arch_enable) (void);
+	void (*arch_disable) (void);
+	void (*arch_reprogram_timer) (void);
+};
+
+extern struct dyn_tick_state * dyn_tick;
+extern void dyn_tick_register(struct dyn_tick_timer * new_timer);
+
+#define NS_TICK_LEN		((1 * 1000000000)/HZ)
+#define DYN_TICK_MIN_SKIP	2
+
+#ifdef CONFIG_NO_IDLE_HZ
+
+extern unsigned long dyn_tick_reprogram_timer(void);
+
+#else
+
+#define arch_has_safe_halt()		0
+#define dyn_tick_reprogram_timer()	{}
+
+
+#endif	/* CONFIG_NO_IDLE_HZ */
+
+/* Pick up arch specific header */
+#include <asm/dyn-tick.h>
+
+#endif	/* _DYN_TICK_TIMER_H */
Index: linux-dev/kernel/Makefile
===================================================================
--- linux-dev.orig/kernel/Makefile	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/kernel/Makefile	2005-06-01 17:54:33.000000000 -0700
@@ -28,6 +28,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o
 obj-$(CONFIG_SYSFS) += ksysfs.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_SECCOMP) += seccomp.o
+obj-$(CONFIG_NO_IDLE_HZ) += dyn-tick.o
 
 ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
Index: linux-dev/kernel/dyn-tick.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-dev/kernel/dyn-tick.c	2005-06-01 18:04:08.000000000 -0700
@@ -0,0 +1,235 @@
+/*
+ * linux/arch/i386/kernel/dyn-tick.c
+ *
+ * Beginnings of generic dynamic tick timer support
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Tony Lindgen <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.
+ */
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sysdev.h>
+#include <linux/interrupt.h>
+#include <linux/cpumask.h>
+#include <linux/pm.h>
+#include <linux/dyn-tick.h>
+#include <asm/io.h>
+
+#include "io_ports.h"
+
+#define DYN_TICK_VERSION	"050602-1"
+
+struct dyn_tick_state dyn_tick_state;
+struct dyn_tick_state * dyn_tick = &dyn_tick_state;
+struct dyn_tick_timer * dyn_tick_cfg;
+static cpumask_t dyn_cpu_map;
+
+/*
+ * Arch independed code needed to reprogram next timer interrupt.
+ * Gets called from cpu_idle() before entering idle loop. Note that
+ * we want to have all processors idle before reprogramming the
+ * next timer interrupt.
+ */
+unsigned long dyn_tick_reprogram_timer(void)
+{
+	int cpu;
+	unsigned long flags;
+	cpumask_t idle_cpus;
+	unsigned long next;
+
+	if (dyn_tick->state & DYN_TICK_DEBUG)
+		printk("i");
+	
+	if (!(dyn_tick->state & DYN_TICK_ENABLED))
+		return 0;
+
+	/* Check if we are already skipping ticks and can idle other cpus */
+	if (dyn_tick->state & DYN_TICK_SKIPPING) {
+		reprogram_apic_timer(dyn_tick->skip);
+		return 0;
+	}
+
+	/* Check if we can start skipping ticks */
+	write_seqlock_irqsave(&xtime_lock, flags);
+	cpu = smp_processor_id();
+	cpu_set(cpu, dyn_cpu_map);
+	cpus_and(idle_cpus, dyn_cpu_map, cpu_online_map);
+	if (cpus_equal(idle_cpus, cpu_online_map)) {
+		next = next_timer_interrupt();
+		if (jiffies > next) {
+			//printk("Too late? next: %lu jiffies: %lu\n",
+			//       next, jjiffies);
+			dyn_tick->skip = 1;
+		} else
+			dyn_tick->skip = next_timer_interrupt() - jiffies;
+		if (dyn_tick->skip > DYN_TICK_MIN_SKIP) {
+			if (dyn_tick->skip > dyn_tick->max_skip)
+				dyn_tick->skip = dyn_tick->max_skip;
+
+			dyn_tick_cfg->arch_reprogram_timer();
+
+			dyn_tick->skip_cpu = cpu;
+			dyn_tick->state |= DYN_TICK_SKIPPING;
+		}
+		cpus_clear(dyn_cpu_map);
+	}
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	return dyn_tick->skip;
+}
+
+void __init dyn_tick_register(struct dyn_tick_timer * arch_timer)
+{
+	dyn_tick_cfg = 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_state(struct sys_device *dev, char *buf)
+{
+	return sprintf(buf, "suitable:\t%i\n"
+		       "enabled:\t%i\n"
+		       "skipping:\t%i\n"
+		       "using APIC:\t%i\n"
+		       "int enabled:\t%i\n"
+		       "debug:\t\t%i\n",
+		       dyn_tick->state & DYN_TICK_SUITABLE,
+		       (dyn_tick->state & DYN_TICK_ENABLED) >> 1,
+		       (dyn_tick->state & DYN_TICK_SKIPPING) >> 2,
+		       (dyn_tick->state & DYN_TICK_USE_APIC) >> 3,
+		       (dyn_tick->state & DYN_TICK_TIMER_INT) >> 4,
+		       (dyn_tick->state & DYN_TICK_DEBUG) >> 31);
+}
+
+static ssize_t set_dyn_tick_state(struct sys_device *dev, const char * buf,
+				size_t count)
+{
+	unsigned long flags;
+	unsigned int enable = simple_strtoul(buf, NULL, 2);
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+	if (enable) {
+		if (dyn_tick_cfg->arch_enable)
+			dyn_tick_cfg->arch_enable();
+		dyn_tick->state |= DYN_TICK_ENABLED;
+	} else {
+		if (dyn_tick_cfg->arch_disable)
+			dyn_tick_cfg->arch_disable();
+		dyn_tick->state &= ~DYN_TICK_ENABLED;
+	}
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	return count;
+}
+
+static SYSDEV_ATTR(dyn_tick_state, 0644, show_dyn_tick_state,
+		   set_dyn_tick_state);
+
+static ssize_t show_dyn_tick_int(struct sys_device *dev, char *buf)
+{
+	return sprintf(buf, "%i\n",
+		       (dyn_tick->state & DYN_TICK_TIMER_INT) >> 4);
+}
+
+static ssize_t set_dyn_tick_int(struct sys_device *dev, const char * buf,
+				size_t count)
+{
+	unsigned long flags;
+	unsigned int enable = simple_strtoul(buf, NULL, 2);
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+	if (enable)
+		dyn_tick->state |= DYN_TICK_TIMER_INT;
+	else
+		dyn_tick->state &= ~DYN_TICK_TIMER_INT;
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	return count;
+}
+
+static SYSDEV_ATTR(dyn_tick_int, 0644, show_dyn_tick_int, set_dyn_tick_int);
+
+static ssize_t show_dyn_tick_dbg(struct sys_device *dev, char *buf)
+{
+	return sprintf(buf, "%i\n",
+		       (dyn_tick->state & DYN_TICK_DEBUG) >> 31);
+}
+
+static ssize_t set_dyn_tick_dbg(struct sys_device *dev, const char * buf,
+				size_t count)
+{
+	unsigned long flags;
+	unsigned int enable = simple_strtoul(buf, NULL, 2);
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+	if (enable)
+		dyn_tick->state |= DYN_TICK_DEBUG;
+	else
+		dyn_tick->state &= ~DYN_TICK_DEBUG;
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	return count;
+}
+
+static SYSDEV_ATTR(dyn_tick_dbg, 0644, show_dyn_tick_dbg, set_dyn_tick_dbg);
+
+/*
+ * ---------------------------------------------------------------------------
+ * Init functions
+ * ---------------------------------------------------------------------------
+ */
+
+static int __init dyn_tick_early_init(void)
+{
+	dyn_tick->state |= DYN_TICK_TIMER_INT;
+   return 0;
+}
+
+subsys_initcall(dyn_tick_early_init);
+
+/*
+ * We need to initialize dynamic tick after calibrate delay
+ */
+static int __init dyn_tick_late_init(void)
+{
+	int ret = 0;
+
+	if (dyn_tick_cfg == NULL || dyn_tick_cfg->arch_init == NULL ||
+	    !(dyn_tick->state & DYN_TICK_SUITABLE)) {
+		printk(KERN_ERR "dyn-tick: No suitable timer found\n");
+		return -ENODEV;
+	}
+
+	ret = dyn_tick_cfg->arch_init();
+	if (ret != 0) {
+		printk(KERN_ERR "dyn-tick: Init failed\n");
+		return -ENODEV;
+	}
+
+	ret = sysdev_create_file(&device_timer, &attr_dyn_tick_state);
+	ret = sysdev_create_file(&device_timer, &attr_dyn_tick_int);
+	ret = sysdev_create_file(&device_timer, &attr_dyn_tick_dbg);
+
+	printk(KERN_INFO "dyn-tick: Timer using dynamic tick\n");
+
+	return ret;
+}
+
+late_initcall(dyn_tick_late_init);
Index: linux-dev/arch/i386/kernel/timers/timer_pit.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/timers/timer_pit.c	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/kernel/timers/timer_pit.c	2005-06-01 17:54:33.000000000 -0700
@@ -149,6 +149,43 @@ static unsigned long get_offset_pit(void
 	return count;
 }
 
+/*
+ * REVISIT: Looks like on P3 APIC timer keeps running if PIT mode
+ *	    is changed. On P4, changing PIT mode seems to kill
+ *	    APIC timer interrupts. Same thing with disabling PIT
+ *	    interrupt.
+ */
+void disable_pit_timer(void)
+{
+	extern spinlock_t i8253_lock;
+	unsigned long flags;
+	spin_lock_irqsave(&i8253_lock, flags);
+	outb_p(0x32, PIT_MODE);		/* binary, mode 1, LSB/MSB, ch 0 */
+	spin_unlock_irqrestore(&i8253_lock, flags);
+}
+
+/*
+ * Reprograms the next timer interrupt
+ * PIT timer reprogramming code taken from APM code.
+ * Note that PIT timer is a 16-bit timer, which allows max
+ * skip of only few seconds.
+ */
+void reprogram_pit_timer(int jiffies_to_skip)
+{
+	int skip;
+	extern spinlock_t i8253_lock;
+	unsigned long flags;
+
+	skip = jiffies_to_skip * LATCH;
+	if (skip > 0xffff)
+		skip = 0xffff;
+
+	spin_lock_irqsave(&i8253_lock, flags);
+	outb_p(0x34, PIT_MODE);		/* binary, mode 2, LSB/MSB, ch 0 */
+	outb_p(skip & 0xff, PIT_CH0);	/* LSB */
+	outb(skip >> 8, PIT_CH0);	/* MSB */
+	spin_unlock_irqrestore(&i8253_lock, flags);
+}
 
 /* tsc timer_opts struct */
 struct timer_opts timer_pit = {

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-1
  2005-06-02  1:36 [PATCH] Dynamic tick for x86 version 050602-1 Tony Lindgren
@ 2005-06-02  1:54 ` Zwane Mwaikambo
  2005-06-02  2:09   ` Tony Lindgren
  2005-06-02  8:30 ` Christian Hesse
  2005-06-07 20:36 ` [PATCH] Dynamic tick for x86 version 050602-1 Jonathan Corbet
  2 siblings, 1 reply; 32+ messages in thread
From: Zwane Mwaikambo @ 2005-06-02  1:54 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-kernel

Hi Tony,

On Wed, 1 Jun 2005, Tony Lindgren wrote:

> Here's an updated version of the dynamic tick patch.
> 
> It's mostly clean-up and it's now using the standard
> monotonic_clock() functions as suggested by John Stultz.
> 
> Please let me know of any issues with the patch. I'll continue to do
> more clean-up on it, but I think the basic functionality is done.
> 
> Thomas, where do you have the latest version of your ACPI idle
> patch? I'd like to add that to the dyn-tick page as well.
> 
> Older patches and some related links are at:
> 
> http://muru.com/linux/dyntick/

Are there any 'known issues' wrt various timer sources with this version?

Thanks,
	Zwane


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-1
  2005-06-02  1:54 ` Zwane Mwaikambo
@ 2005-06-02  2:09   ` Tony Lindgren
  0 siblings, 0 replies; 32+ messages in thread
From: Tony Lindgren @ 2005-06-02  2:09 UTC (permalink / raw)
  To: Zwane Mwaikambo; +Cc: linux-kernel

* Zwane Mwaikambo <zwane@arm.linux.org.uk> [050601 18:51]:
> Hi Tony,
> 
> On Wed, 1 Jun 2005, Tony Lindgren wrote:
> 
> > Here's an updated version of the dynamic tick patch.
> > 
> > It's mostly clean-up and it's now using the standard
> > monotonic_clock() functions as suggested by John Stultz.
> > 
> > Please let me know of any issues with the patch. I'll continue to do
> > more clean-up on it, but I think the basic functionality is done.
> > 
> > Thomas, where do you have the latest version of your ACPI idle
> > patch? I'd like to add that to the dyn-tick page as well.
> > 
> > Older patches and some related links are at:
> > 
> > http://muru.com/linux/dyntick/
> 
> Are there any 'known issues' wrt various timer sources with this version?

AFAIK, these are the remaining issues:

Supported timers are ACPI PM timer and TSC timer. No support for
CONFIG_HPET yet. Anybody feel like adding the HPET support? I don't
have any machines with HPET.

Lost tick code is currently disabled with #ifndef CONFIG_NO_IDLE_HZ
in timer_pm.c and timer_tsc.c. This should be done based on some
variable instead.

Kconfig option DYN_TICK_USE_APIC should be converted to a command
line option, as it only seems to work on P3 and not on P4.

So actually let's say the basic functionality is still missing
some parts :) But these should be pretty easy to fix.

Tony

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-1
  2005-06-02  1:36 [PATCH] Dynamic tick for x86 version 050602-1 Tony Lindgren
  2005-06-02  1:54 ` Zwane Mwaikambo
@ 2005-06-02  8:30 ` Christian Hesse
  2005-06-02 17:42   ` [PATCH] Dynamic tick for x86 version 050602-2 Tony Lindgren
  2005-06-07 20:36 ` [PATCH] Dynamic tick for x86 version 050602-1 Jonathan Corbet
  2 siblings, 1 reply; 32+ messages in thread
From: Christian Hesse @ 2005-06-02  8:30 UTC (permalink / raw)
  To: linux-kernel; +Cc: Tony Lindgren

[-- Attachment #1: Type: text/plain, Size: 2073 bytes --]

On Thursday 02 June 2005 03:36, Tony Lindgren wrote:
> Hi all,
>
> Here's an updated version of the dynamic tick patch.
>
> It's mostly clean-up and it's now using the standard
> monotonic_clock() functions as suggested by John Stultz.
>
> Please let me know of any issues with the patch. I'll continue to do
> more clean-up on it, but I think the basic functionality is done.

I would like to test it, but have some trouble. The patch applies cleanly and 
everything compiles fine, but linking fails:

# ld -m elf_i386  -R arch/i386/kernel/vsyscall-syms.o -r -o 
arch/i386/kernel/built-in.o arch/i386/kernel/process.o 
arch/i386/kernel/semaphore.o arch/i386/kernel/signal.o 
arch/i386/kernel/entry.o arch/i386/kernel/traps.o arch/i386/kernel/irq.o 
arch/i386/kernel/vm86.o arch/i386/kernel/ptrace.o arch/i386/kernel/time.o 
arch/i386/kernel/ioport.o arch/i386/kernel/ldt.o arch/i386/kernel/setup.o 
arch/i386/kernel/i8259.o arch/i386/kernel/sys_i386.o 
arch/i386/kernel/pci-dma.o arch/i386/kernel/i386_ksyms.o 
arch/i386/kernel/i387.o arch/i386/kernel/dmi_scan.o 
arch/i386/kernel/bootflag.o arch/i386/kernel/doublefault.o 
arch/i386/kernel/quirks.o arch/i386/kernel/cpu/built-in.o 
arch/i386/kernel/timers/built-in.o arch/i386/kernel/acpi/built-in.o 
arch/i386/kernel/reboot.o arch/i386/kernel/module.o 
arch/i386/kernel/sysenter.o arch/i386/kernel/vsyscall.o 
arch/i386/kernel/dyn-tick.o arch/i386/kernel/early_printk.o
arch/i386/kernel/irq.o: In function `reprogram_apic_timer':
irq.c:(.text+0x0): multiple definition of `reprogram_apic_timer'
arch/i386/kernel/process.o:process.c:(.text+0x0): first defined here
arch/i386/kernel/time.o: In function `reprogram_apic_timer':
time.c:(.text+0x0): multiple definition of `reprogram_apic_timer'
arch/i386/kernel/process.o:process.c:(.text+0x0): first defined here
arch/i386/kernel/dyn-tick.o: In function `reprogram_apic_timer':
dyn-tick.c:(.text+0x0): multiple definition of `reprogram_apic_timer'
arch/i386/kernel/process.o:process.c:(.text+0x0): first defined here

-- 
Christian

[-- Attachment #2: Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-2
  2005-06-02  8:30 ` Christian Hesse
@ 2005-06-02 17:42   ` Tony Lindgren
  2005-06-02 20:03     ` Christian Hesse
  2005-06-03 22:37     ` Pavel Machek
  0 siblings, 2 replies; 32+ messages in thread
From: Tony Lindgren @ 2005-06-02 17:42 UTC (permalink / raw)
  To: Christian Hesse; +Cc: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2286 bytes --]

* Christian Hesse <mail@earthworm.de> [050602 01:31]:
> On Thursday 02 June 2005 03:36, Tony Lindgren wrote:
> > Hi all,
> >
> > Here's an updated version of the dynamic tick patch.
> >
> > It's mostly clean-up and it's now using the standard
> > monotonic_clock() functions as suggested by John Stultz.
> >
> > Please let me know of any issues with the patch. I'll continue to do
> > more clean-up on it, but I think the basic functionality is done.
> 
> I would like to test it, but have some trouble. The patch applies cleanly and 
> everything compiles fine, but linking fails:
> 
> # ld -m elf_i386  -R arch/i386/kernel/vsyscall-syms.o -r -o 
> arch/i386/kernel/built-in.o arch/i386/kernel/process.o 
> arch/i386/kernel/semaphore.o arch/i386/kernel/signal.o 
> arch/i386/kernel/entry.o arch/i386/kernel/traps.o arch/i386/kernel/irq.o 
> arch/i386/kernel/vm86.o arch/i386/kernel/ptrace.o arch/i386/kernel/time.o 
> arch/i386/kernel/ioport.o arch/i386/kernel/ldt.o arch/i386/kernel/setup.o 
> arch/i386/kernel/i8259.o arch/i386/kernel/sys_i386.o 
> arch/i386/kernel/pci-dma.o arch/i386/kernel/i386_ksyms.o 
> arch/i386/kernel/i387.o arch/i386/kernel/dmi_scan.o 
> arch/i386/kernel/bootflag.o arch/i386/kernel/doublefault.o 
> arch/i386/kernel/quirks.o arch/i386/kernel/cpu/built-in.o 
> arch/i386/kernel/timers/built-in.o arch/i386/kernel/acpi/built-in.o 
> arch/i386/kernel/reboot.o arch/i386/kernel/module.o 
> arch/i386/kernel/sysenter.o arch/i386/kernel/vsyscall.o 
> arch/i386/kernel/dyn-tick.o arch/i386/kernel/early_printk.o
> arch/i386/kernel/irq.o: In function `reprogram_apic_timer':
> irq.c:(.text+0x0): multiple definition of `reprogram_apic_timer'
> arch/i386/kernel/process.o:process.c:(.text+0x0): first defined here
> arch/i386/kernel/time.o: In function `reprogram_apic_timer':
> time.c:(.text+0x0): multiple definition of `reprogram_apic_timer'
> arch/i386/kernel/process.o:process.c:(.text+0x0): first defined here
> arch/i386/kernel/dyn-tick.o: In function `reprogram_apic_timer':
> dyn-tick.c:(.text+0x0): multiple definition of `reprogram_apic_timer'
> arch/i386/kernel/process.o:process.c:(.text+0x0): first defined here

Should be fixed now, the header was defining it as a function un UP
system with no local apic. Can you try the following version?

Tony



[-- Attachment #2: patch-dynamic-tick-2.6.12-rc5-050602-2 --]
[-- Type: text/plain, Size: 26163 bytes --]

Index: linux-dev/arch/i386/Kconfig
===================================================================
--- linux-dev.orig/arch/i386/Kconfig	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/Kconfig	2005-06-01 17:54:32.000000000 -0700
@@ -458,6 +458,26 @@ config HPET_EMULATE_RTC
 	bool "Provide RTC interrupt"
 	depends on HPET_TIMER && RTC=y
 
+config NO_IDLE_HZ
+	bool "Dynamic Tick Timer - Skip timer ticks during idle"
+	help
+	  This option enables support for skipping timer ticks when the
+	  processor is idle. During system load, timer is continuous.
+	  This option saves power, as it allows the system to stay in
+	  idle mode longer. Currently supported timers are ACPI PM
+	  timer, local APIC timer, and TSC timer. HPET timer is currently
+	  not supported.
+
+config DYN_TICK_USE_APIC
+	bool "Use APIC timer instead of PIT timer"
+	help
+	  This option enables using APIC timer interrupt if your hardware
+	  supports it. APIC timer allows longer sleep periods compared
+	  to PIT timer. Note that on some hardware disabling PIT timer
+	  also disables APIC timer interrupts, and system won't run
+	  properly. Symptoms include slow system boot, and time running
+	  slow. If unsure, don't enable this option.
+
 config SMP
 	bool "Symmetric multi-processing support"
 	---help---
Index: linux-dev/arch/i386/kernel/Makefile
===================================================================
--- linux-dev.orig/arch/i386/kernel/Makefile	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/kernel/Makefile	2005-06-01 17:54:32.000000000 -0700
@@ -31,6 +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-$(CONFIG_EFI) 		+= efi.o efi_stub.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 
Index: linux-dev/arch/i386/kernel/apic.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/apic.c	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/kernel/apic.c	2005-06-01 17:54:32.000000000 -0700
@@ -26,6 +26,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/kernel_stat.h>
 #include <linux/sysdev.h>
+#include <linux/dyn-tick.h>
 
 #include <asm/atomic.h>
 #include <asm/smp.h>
@@ -909,6 +910,8 @@ void (*wait_timer_tick)(void) __initdata
 
 #define APIC_DIVISOR 16
 
+static u32 apic_timer_val;
+
 static void __setup_APIC_LVTT(unsigned int clocks)
 {
 	unsigned int lvtt_value, tmp_value, ver;
@@ -927,7 +930,15 @@ static void __setup_APIC_LVTT(unsigned i
 				& ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
 				| APIC_TDR_DIV_16);
 
-	apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR);
+	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
+
+	apic_write_around(APIC_TMICT, apic_timer_val);
 }
 
 static void __init setup_APIC_timer(unsigned int clocks)
@@ -1040,6 +1051,13 @@ 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
+
 	local_irq_enable();
 }
 
@@ -1068,6 +1086,18 @@ 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.
@@ -1160,6 +1190,7 @@ inline void smp_local_timer_interrupt(st
 
 fastcall void smp_apic_timer_interrupt(struct pt_regs *regs)
 {
+	unsigned long seq;
 	int cpu = smp_processor_id();
 
 	/*
@@ -1178,6 +1209,23 @@ fastcall void smp_apic_timer_interrupt(s
 	 * interrupt lock, which is the WrongThing (tm) to do.
 	 */
 	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
+
 	smp_local_timer_interrupt(regs);
 	irq_exit();
 }
Index: linux-dev/arch/i386/kernel/dyn-tick.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-dev/arch/i386/kernel/dyn-tick.c	2005-06-01 17:58:43.000000000 -0700
@@ -0,0 +1,45 @@
+/*
+ * linux/arch/i386/kernel/dyn-tick.c
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Tony Lindgen <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.
+ */
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/dyn-tick.h>
+
+void arch_reprogram_timer(void)
+{
+	if (cpu_has_local_apic()) {
+		disable_pit_timer();
+		if (dyn_tick->state & DYN_TICK_TIMER_INT)
+			reprogram_apic_timer(dyn_tick->skip);
+	} else {
+		if (dyn_tick->state & DYN_TICK_TIMER_INT)
+			reprogram_pit_timer(dyn_tick->skip);
+		else
+			disable_pit_timer();
+	}
+}
+
+static struct dyn_tick_timer arch_dyn_tick_timer = {
+	.arch_reprogram_timer	= &arch_reprogram_timer,
+};
+
+int __init dyn_tick_init(void)
+{
+	arch_dyn_tick_timer.arch_init = dyn_tick_arch_init;
+	dyn_tick_register(&arch_dyn_tick_timer);
+
+	return 0;
+}
+arch_initcall(dyn_tick_init);
Index: linux-dev/include/asm-i386/dyn-tick.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-dev/include/asm-i386/dyn-tick.h	2005-06-02 10:18:44.000000000 -0700
@@ -0,0 +1,42 @@
+/*
+ * linux/include/asm-i386/dyn-tick.h
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Tony Lindgen <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.
+ */
+
+#ifndef _ASM_I386_DYN_TICK_H_
+#define _ASM_I386_DYN_TICK_H_
+
+extern int dyn_tick_arch_init(void);
+extern void disable_pit_timer(void);
+extern void reprogram_pit_timer(int jiffies_to_skip);
+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)	{}
+#endif
+
+#undef DEBUG
+#ifdef DEBUG
+#define dbg_dyn_tick_irq() {if (skipped && skipped < dyn_tick->skip) \
+				printk("%u/%li ", skipped, dyn_tick->skip);}
+#else
+#define dbg_dyn_tick_irq() {}
+#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)
+#else
+#define cpu_has_local_apic()	0
+#endif
+
+#endif /* _ASM_I386_DYN_TICK_H_ */
Index: linux-dev/arch/i386/kernel/irq.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/irq.c	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/kernel/irq.c	2005-06-01 17:54:32.000000000 -0700
@@ -15,6 +15,7 @@
 #include <linux/seq_file.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
+#include <linux/dyn-tick.h>
 
 DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_maxaligned_in_smp;
 EXPORT_PER_CPU_SYMBOL(irq_stat);
@@ -102,6 +103,12 @@ fastcall unsigned int do_IRQ(struct pt_r
 		);
 	} else
 #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
+
 		__do_IRQ(irq, regs);
 
 	irq_exit();
Index: linux-dev/arch/i386/kernel/process.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/process.c	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/kernel/process.c	2005-06-01 17:54:32.000000000 -0700
@@ -37,6 +37,7 @@
 #include <linux/kallsyms.h>
 #include <linux/ptrace.h>
 #include <linux/random.h>
+#include <linux/dyn-tick.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -160,6 +161,10 @@ void cpu_idle (void)
 			if (!idle)
 				idle = default_idle;
 
+#ifdef CONFIG_NO_IDLE_HZ
+			dyn_tick_reprogram_timer();
+#endif
+
 			__get_cpu_var(irq_stat).idle_timestamp = jiffies;
 			idle();
 		}
Index: linux-dev/arch/i386/kernel/time.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/time.c	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/kernel/time.c	2005-06-01 17:59:25.000000000 -0700
@@ -46,6 +46,7 @@
 #include <linux/bcd.h>
 #include <linux/efi.h>
 #include <linux/mca.h>
+#include <linux/dyn-tick.h>
 
 #include <asm/io.h>
 #include <asm/smp.h>
@@ -308,6 +309,51 @@ 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;
+
+	if (dyn_tick->state & DYN_TICK_DEBUG) {
+		if (irq == 0)
+			printk(".");
+		else
+			printk("%i ", irq);
+	}
+
+	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)) {
+		dbg_dyn_tick_irq();
+		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)
 {
@@ -416,7 +462,7 @@ static struct sysdev_class timer_sysclas
 
 
 /* XXX this driverfs stuff should probably go elsewhere later -john */
-static struct sys_device device_timer = {
+struct sys_device device_timer = {
 	.id	= 0,
 	.cls	= &timer_sysclass,
 };
@@ -452,6 +498,32 @@ 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 (!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);
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+	dyn_tick->state |= DYN_TICK_ENABLED;
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	return 0;
+}
+#endif	/* CONFIG_NO_IDLE_HZ */
+
 void __init time_init(void)
 {
 #ifdef CONFIG_HPET_TIMER
@@ -472,5 +544,16 @@ 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
+
 	time_init_hook();
 }
Index: linux-dev/arch/i386/kernel/timers/timer_pm.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/timers/timer_pm.c	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/kernel/timers/timer_pm.c	2005-06-01 17:54:32.000000000 -0700
@@ -168,6 +168,7 @@ static void mark_offset_pmtmr(void)
 	monotonic_base += delta * NSEC_PER_USEC;
 	write_sequnlock(&monotonic_lock);
 
+#ifndef CONFIG_NO_IDLE_HZ
 	/* convert to ticks */
 	delta += offset_delay;
 	lost = delta / (USEC_PER_SEC / HZ);
@@ -184,6 +185,7 @@ static void mark_offset_pmtmr(void)
 		first_run = 0;
 		offset_delay = 0;
 	}
+#endif
 }
 
 
Index: linux-dev/arch/i386/kernel/timers/timer_tsc.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/timers/timer_tsc.c	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/kernel/timers/timer_tsc.c	2005-06-01 17:54:32.000000000 -0700
@@ -348,6 +348,7 @@ static void mark_offset_tsc(void)
 
 	rdtsc(last_tsc_low, last_tsc_high);
 
+#ifndef CONFIG_NO_IDLE_HZ
 	spin_lock(&i8253_lock);
 	outb_p(0x00, PIT_MODE);     /* latch the count ASAP */
 
@@ -415,11 +416,14 @@ static void mark_offset_tsc(void)
 			cpufreq_delayed_get();
 	} else
 		lost_count = 0;
+#endif
+
 	/* update the monotonic base value */
 	this_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
 	monotonic_base += cycles_2_ns(this_offset - last_offset);
 	write_sequnlock(&monotonic_lock);
 
+#ifndef CONFIG_NO_IDLE_HZ
 	/* calculate delay_at_last_interrupt */
 	count = ((LATCH-1) - count) * TICK_SIZE;
 	delay_at_last_interrupt = (count + LATCH/2) / LATCH;
@@ -430,6 +434,7 @@ static void mark_offset_tsc(void)
 	 */
 	if (lost && abs(delay - delay_at_last_interrupt) > (900000/HZ))
 		jiffies_64++;
+#endif
 }
 
 static int __init init_tsc(char* override)
Index: linux-dev/arch/i386/mach-default/setup.c
===================================================================
--- linux-dev.orig/arch/i386/mach-default/setup.c	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/mach-default/setup.c	2005-06-01 17:54:32.000000000 -0700
@@ -85,6 +85,22 @@ void __init time_init_hook(void)
 	setup_irq(0, &irq0);
 }
 
+/**
+ * replace_timer_interrupt - allow replacing timer interrupt handler
+ *
+ * Description:
+ *	Can be used to replace timer interrupt handler with a more optimized
+ *	handler. Used for enabling and disabling of CONFIG_NO_IDLE_HZ.
+ */
+void replace_timer_interrupt(void * new_handler)
+{
+	unsigned long flags;
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+	irq0.handler = new_handler;
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+}
+
 #ifdef CONFIG_MCA
 /**
  * mca_nmi_hook - hook into MCA specific NMI chain
Index: linux-dev/include/linux/dyn-tick.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-dev/include/linux/dyn-tick.h	2005-06-01 17:54:33.000000000 -0700
@@ -0,0 +1,62 @@
+/*
+ * linux/include/linux/dyn-tick.h
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Tony Lindgen <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.
+ */
+
+#ifndef _DYN_TICK_TIMER_H
+#define _DYN_TICK_TIMER_H
+
+#include <linux/interrupt.h>
+
+#define DYN_TICK_DEBUG		(1 << 31)
+#define DYN_TICK_TIMER_INT	(1 << 4)
+#define DYN_TICK_USE_APIC	(1 << 3)
+#define DYN_TICK_SKIPPING	(1 << 2)
+#define DYN_TICK_ENABLED	(1 << 1)
+#define DYN_TICK_SUITABLE	(1 << 0)
+
+struct dyn_tick_state {
+	unsigned int state;		/* Current state */
+	int skip_cpu;			/* Skip handling processor */
+	unsigned long skip;		/* Ticks to skip */
+	unsigned int max_skip;		/* Max number of ticks to skip */
+	unsigned long irq_skip_mask;	/* Do not update time from these irqs */
+	irqreturn_t (*interrupt)(int, void *, struct pt_regs *);
+};
+
+struct dyn_tick_timer {
+	int (*arch_init) (void);
+	void (*arch_enable) (void);
+	void (*arch_disable) (void);
+	void (*arch_reprogram_timer) (void);
+};
+
+extern struct dyn_tick_state * dyn_tick;
+extern void dyn_tick_register(struct dyn_tick_timer * new_timer);
+
+#define NS_TICK_LEN		((1 * 1000000000)/HZ)
+#define DYN_TICK_MIN_SKIP	2
+
+#ifdef CONFIG_NO_IDLE_HZ
+
+extern unsigned long dyn_tick_reprogram_timer(void);
+
+#else
+
+#define arch_has_safe_halt()		0
+#define dyn_tick_reprogram_timer()	{}
+
+
+#endif	/* CONFIG_NO_IDLE_HZ */
+
+/* Pick up arch specific header */
+#include <asm/dyn-tick.h>
+
+#endif	/* _DYN_TICK_TIMER_H */
Index: linux-dev/kernel/Makefile
===================================================================
--- linux-dev.orig/kernel/Makefile	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/kernel/Makefile	2005-06-01 17:54:33.000000000 -0700
@@ -28,6 +28,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o
 obj-$(CONFIG_SYSFS) += ksysfs.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_SECCOMP) += seccomp.o
+obj-$(CONFIG_NO_IDLE_HZ) += dyn-tick.o
 
 ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
Index: linux-dev/kernel/dyn-tick.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-dev/kernel/dyn-tick.c	2005-06-02 10:37:12.000000000 -0700
@@ -0,0 +1,235 @@
+/*
+ * linux/arch/i386/kernel/dyn-tick.c
+ *
+ * Beginnings of generic dynamic tick timer support
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Tony Lindgen <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.
+ */
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sysdev.h>
+#include <linux/interrupt.h>
+#include <linux/cpumask.h>
+#include <linux/pm.h>
+#include <linux/dyn-tick.h>
+#include <asm/io.h>
+
+#include "io_ports.h"
+
+#define DYN_TICK_VERSION	"050602-2"
+
+struct dyn_tick_state dyn_tick_state;
+struct dyn_tick_state * dyn_tick = &dyn_tick_state;
+struct dyn_tick_timer * dyn_tick_cfg;
+static cpumask_t dyn_cpu_map;
+
+/*
+ * Arch independed code needed to reprogram next timer interrupt.
+ * Gets called from cpu_idle() before entering idle loop. Note that
+ * we want to have all processors idle before reprogramming the
+ * next timer interrupt.
+ */
+unsigned long dyn_tick_reprogram_timer(void)
+{
+	int cpu;
+	unsigned long flags;
+	cpumask_t idle_cpus;
+	unsigned long next;
+
+	if (dyn_tick->state & DYN_TICK_DEBUG)
+		printk("i");
+	
+	if (!(dyn_tick->state & DYN_TICK_ENABLED))
+		return 0;
+
+	/* Check if we are already skipping ticks and can idle other cpus */
+	if (dyn_tick->state & DYN_TICK_SKIPPING) {
+		reprogram_apic_timer(dyn_tick->skip);
+		return 0;
+	}
+
+	/* Check if we can start skipping ticks */
+	write_seqlock_irqsave(&xtime_lock, flags);
+	cpu = smp_processor_id();
+	cpu_set(cpu, dyn_cpu_map);
+	cpus_and(idle_cpus, dyn_cpu_map, cpu_online_map);
+	if (cpus_equal(idle_cpus, cpu_online_map)) {
+		next = next_timer_interrupt();
+		if (jiffies > next) {
+			//printk("Too late? next: %lu jiffies: %lu\n",
+			//       next, jjiffies);
+			dyn_tick->skip = 1;
+		} else
+			dyn_tick->skip = next_timer_interrupt() - jiffies;
+		if (dyn_tick->skip > DYN_TICK_MIN_SKIP) {
+			if (dyn_tick->skip > dyn_tick->max_skip)
+				dyn_tick->skip = dyn_tick->max_skip;
+
+			dyn_tick_cfg->arch_reprogram_timer();
+
+			dyn_tick->skip_cpu = cpu;
+			dyn_tick->state |= DYN_TICK_SKIPPING;
+		}
+		cpus_clear(dyn_cpu_map);
+	}
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	return dyn_tick->skip;
+}
+
+void __init dyn_tick_register(struct dyn_tick_timer * arch_timer)
+{
+	dyn_tick_cfg = 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_state(struct sys_device *dev, char *buf)
+{
+	return sprintf(buf, "suitable:\t%i\n"
+		       "enabled:\t%i\n"
+		       "skipping:\t%i\n"
+		       "using APIC:\t%i\n"
+		       "int enabled:\t%i\n"
+		       "debug:\t\t%i\n",
+		       dyn_tick->state & DYN_TICK_SUITABLE,
+		       (dyn_tick->state & DYN_TICK_ENABLED) >> 1,
+		       (dyn_tick->state & DYN_TICK_SKIPPING) >> 2,
+		       (dyn_tick->state & DYN_TICK_USE_APIC) >> 3,
+		       (dyn_tick->state & DYN_TICK_TIMER_INT) >> 4,
+		       (dyn_tick->state & DYN_TICK_DEBUG) >> 31);
+}
+
+static ssize_t set_dyn_tick_state(struct sys_device *dev, const char * buf,
+				size_t count)
+{
+	unsigned long flags;
+	unsigned int enable = simple_strtoul(buf, NULL, 2);
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+	if (enable) {
+		if (dyn_tick_cfg->arch_enable)
+			dyn_tick_cfg->arch_enable();
+		dyn_tick->state |= DYN_TICK_ENABLED;
+	} else {
+		if (dyn_tick_cfg->arch_disable)
+			dyn_tick_cfg->arch_disable();
+		dyn_tick->state &= ~DYN_TICK_ENABLED;
+	}
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	return count;
+}
+
+static SYSDEV_ATTR(dyn_tick_state, 0644, show_dyn_tick_state,
+		   set_dyn_tick_state);
+
+static ssize_t show_dyn_tick_int(struct sys_device *dev, char *buf)
+{
+	return sprintf(buf, "%i\n",
+		       (dyn_tick->state & DYN_TICK_TIMER_INT) >> 4);
+}
+
+static ssize_t set_dyn_tick_int(struct sys_device *dev, const char * buf,
+				size_t count)
+{
+	unsigned long flags;
+	unsigned int enable = simple_strtoul(buf, NULL, 2);
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+	if (enable)
+		dyn_tick->state |= DYN_TICK_TIMER_INT;
+	else
+		dyn_tick->state &= ~DYN_TICK_TIMER_INT;
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	return count;
+}
+
+static SYSDEV_ATTR(dyn_tick_int, 0644, show_dyn_tick_int, set_dyn_tick_int);
+
+static ssize_t show_dyn_tick_dbg(struct sys_device *dev, char *buf)
+{
+	return sprintf(buf, "%i\n",
+		       (dyn_tick->state & DYN_TICK_DEBUG) >> 31);
+}
+
+static ssize_t set_dyn_tick_dbg(struct sys_device *dev, const char * buf,
+				size_t count)
+{
+	unsigned long flags;
+	unsigned int enable = simple_strtoul(buf, NULL, 2);
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+	if (enable)
+		dyn_tick->state |= DYN_TICK_DEBUG;
+	else
+		dyn_tick->state &= ~DYN_TICK_DEBUG;
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	return count;
+}
+
+static SYSDEV_ATTR(dyn_tick_dbg, 0644, show_dyn_tick_dbg, set_dyn_tick_dbg);
+
+/*
+ * ---------------------------------------------------------------------------
+ * Init functions
+ * ---------------------------------------------------------------------------
+ */
+
+static int __init dyn_tick_early_init(void)
+{
+	dyn_tick->state |= DYN_TICK_TIMER_INT;
+   return 0;
+}
+
+subsys_initcall(dyn_tick_early_init);
+
+/*
+ * We need to initialize dynamic tick after calibrate delay
+ */
+static int __init dyn_tick_late_init(void)
+{
+	int ret = 0;
+
+	if (dyn_tick_cfg == NULL || dyn_tick_cfg->arch_init == NULL ||
+	    !(dyn_tick->state & DYN_TICK_SUITABLE)) {
+		printk(KERN_ERR "dyn-tick: No suitable timer found\n");
+		return -ENODEV;
+	}
+
+	ret = dyn_tick_cfg->arch_init();
+	if (ret != 0) {
+		printk(KERN_ERR "dyn-tick: Init failed\n");
+		return -ENODEV;
+	}
+
+	ret = sysdev_create_file(&device_timer, &attr_dyn_tick_state);
+	ret = sysdev_create_file(&device_timer, &attr_dyn_tick_int);
+	ret = sysdev_create_file(&device_timer, &attr_dyn_tick_dbg);
+
+	printk(KERN_INFO "dyn-tick: Timer using dynamic tick\n");
+
+	return ret;
+}
+
+late_initcall(dyn_tick_late_init);
Index: linux-dev/arch/i386/kernel/timers/timer_pit.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/timers/timer_pit.c	2005-06-01 17:51:36.000000000 -0700
+++ linux-dev/arch/i386/kernel/timers/timer_pit.c	2005-06-01 17:54:33.000000000 -0700
@@ -149,6 +149,43 @@ static unsigned long get_offset_pit(void
 	return count;
 }
 
+/*
+ * REVISIT: Looks like on P3 APIC timer keeps running if PIT mode
+ *	    is changed. On P4, changing PIT mode seems to kill
+ *	    APIC timer interrupts. Same thing with disabling PIT
+ *	    interrupt.
+ */
+void disable_pit_timer(void)
+{
+	extern spinlock_t i8253_lock;
+	unsigned long flags;
+	spin_lock_irqsave(&i8253_lock, flags);
+	outb_p(0x32, PIT_MODE);		/* binary, mode 1, LSB/MSB, ch 0 */
+	spin_unlock_irqrestore(&i8253_lock, flags);
+}
+
+/*
+ * Reprograms the next timer interrupt
+ * PIT timer reprogramming code taken from APM code.
+ * Note that PIT timer is a 16-bit timer, which allows max
+ * skip of only few seconds.
+ */
+void reprogram_pit_timer(int jiffies_to_skip)
+{
+	int skip;
+	extern spinlock_t i8253_lock;
+	unsigned long flags;
+
+	skip = jiffies_to_skip * LATCH;
+	if (skip > 0xffff)
+		skip = 0xffff;
+
+	spin_lock_irqsave(&i8253_lock, flags);
+	outb_p(0x34, PIT_MODE);		/* binary, mode 2, LSB/MSB, ch 0 */
+	outb_p(skip & 0xff, PIT_CH0);	/* LSB */
+	outb(skip >> 8, PIT_CH0);	/* MSB */
+	spin_unlock_irqrestore(&i8253_lock, flags);
+}
 
 /* tsc timer_opts struct */
 struct timer_opts timer_pit = {

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-2
  2005-06-02 17:42   ` [PATCH] Dynamic tick for x86 version 050602-2 Tony Lindgren
@ 2005-06-02 20:03     ` Christian Hesse
  2005-06-02 20:32       ` Tony Lindgren
  2005-06-05  4:06       ` Bernard Blackham
  2005-06-03 22:37     ` Pavel Machek
  1 sibling, 2 replies; 32+ messages in thread
From: Christian Hesse @ 2005-06-02 20:03 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1661 bytes --]

On Thursday 02 June 2005 19:42, Tony Lindgren wrote:
> * Christian Hesse <mail@earthworm.de> [050602 01:31]:
> > On Thursday 02 June 2005 03:36, Tony Lindgren wrote:
> > > Hi all,
> > >
> > > Here's an updated version of the dynamic tick patch.
> > >
> > > It's mostly clean-up and it's now using the standard
> > > monotonic_clock() functions as suggested by John Stultz.
> > >
> > > Please let me know of any issues with the patch. I'll continue to do
> > > more clean-up on it, but I think the basic functionality is done.
> >
> > I would like to test it, but have some trouble. The patch applies cleanly
> > and everything compiles fine, but linking fails:
> >
> > [ linker errors ]
>
> Should be fixed now, the header was defining it as a function un UP
> system with no local apic. Can you try the following version?

This one compiles and links without problems.

The reason I want to use this patch is that I hear a high pitched noise [1] 
when running with 1000Hz and the processor is idle. With this patch I could 
use 1000Hz without any noise.

But I found some problems on my system:

- time does not run the correct speed, it was some minutes in future after I 
had compiled a new kernel

- pressing a key on the keyboard sometimes results in two or more characters, 
not only one

- mouse misses some events, e.g. clicks are not recognized (synaptics 
touchpad)

- using software suspend 2.1.8.10 I can suspend the system, but it hangs while 
resuming

Anyway, thanks for your great work! Let me know if you have new versions to 
test.

[1] http://bugme.osdl.org/show_bug.cgi?id=2478

-- 
Christian

[-- Attachment #2: Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-2
  2005-06-02 20:03     ` Christian Hesse
@ 2005-06-02 20:32       ` Tony Lindgren
  2005-06-03  6:08         ` Christian Hesse
  2005-06-05  4:06       ` Bernard Blackham
  1 sibling, 1 reply; 32+ messages in thread
From: Tony Lindgren @ 2005-06-02 20:32 UTC (permalink / raw)
  To: Christian Hesse; +Cc: linux-kernel

* Christian Hesse <mail@earthworm.de> [050602 13:04]:
> On Thursday 02 June 2005 19:42, Tony Lindgren wrote:
> > * Christian Hesse <mail@earthworm.de> [050602 01:31]:
> > > On Thursday 02 June 2005 03:36, Tony Lindgren wrote:
> > > > Hi all,
> > > >
> > > > Here's an updated version of the dynamic tick patch.
> > > >
> > > > It's mostly clean-up and it's now using the standard
> > > > monotonic_clock() functions as suggested by John Stultz.
> > > >
> > > > Please let me know of any issues with the patch. I'll continue to do
> > > > more clean-up on it, but I think the basic functionality is done.
> > >
> > > I would like to test it, but have some trouble. The patch applies cleanly
> > > and everything compiles fine, but linking fails:
> > >
> > > [ linker errors ]
> >
> > Should be fixed now, the header was defining it as a function un UP
> > system with no local apic. Can you try the following version?
> 
> This one compiles and links without problems.
> 
> The reason I want to use this patch is that I hear a high pitched noise [1] 
> when running with 1000Hz and the processor is idle. With this patch I could 
> use 1000Hz without any noise.

Heh!

> But I found some problems on my system:
> 
> - time does not run the correct speed, it was some minutes in future after I 
> had compiled a new kernel

Could you please post output of the following commands:

$ dmesg | grep -i "time\|tick\|apic"

# for i in 1 2 3 4 5; do ntpdate -b someserver.somewhere && sleep 10; done

Also, please attach your .config file too.

> - pressing a key on the keyboard sometimes results in two or more characters, 
> not only one
>
> - mouse misses some events, e.g. clicks are not recognized (synaptics 
> touchpad)
> 
> - using software suspend 2.1.8.10 I can suspend the system, but it hangs while 
> resuming

None of this should happen...

Tony

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-2
  2005-06-02 20:32       ` Tony Lindgren
@ 2005-06-03  6:08         ` Christian Hesse
  2005-06-03 17:39           ` Tony Lindgren
  0 siblings, 1 reply; 32+ messages in thread
From: Christian Hesse @ 2005-06-03  6:08 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-kernel


[-- Attachment #1.1: Type: text/plain, Size: 3674 bytes --]

On Thursday 02 June 2005 22:32, Tony Lindgren wrote:
> * Christian Hesse <mail@earthworm.de> [050602 13:04]:
> > On Thursday 02 June 2005 19:42, Tony Lindgren wrote:
> > > * Christian Hesse <mail@earthworm.de> [050602 01:31]:
> > > > On Thursday 02 June 2005 03:36, Tony Lindgren wrote:
> > > > > Hi all,
> > > > >
> > > > > Here's an updated version of the dynamic tick patch.
> > > > >
> > > > > It's mostly clean-up and it's now using the standard
> > > > > monotonic_clock() functions as suggested by John Stultz.
> > > > >
> > > > > Please let me know of any issues with the patch. I'll continue to
> > > > > do more clean-up on it, but I think the basic functionality is
> > > > > done.
> > > >
> > > > I would like to test it, but have some trouble. The patch applies
> > > > cleanly and everything compiles fine, but linking fails:
> > > >
> > > > [ linker errors ]
> > >
> > > Should be fixed now, the header was defining it as a function un UP
> > > system with no local apic. Can you try the following version?
> >
> > This one compiles and links without problems.
> >
> > The reason I want to use this patch is that I hear a high pitched noise
> > [1] when running with 1000Hz and the processor is idle. With this patch I
> > could use 1000Hz without any noise.
>
> Heh!
>
> > But I found some problems on my system:
> >
> > - time does not run the correct speed, it was some minutes in future
> > after I had compiled a new kernel
>
> Could you please post output of the following commands:
>
> $ dmesg | grep -i "time\|tick\|apic"

The problems occured with enabled CONFIG_DYN_TICK_USE_APIC. As I recompiled 
the kernel the following is without the option. Everything looks good so far 
(except resume...), so I am not shure what caused the bad behavior.

BTW, I can enable CONFIG_DYN_TICK_USE_APIC without CONFIG_X86_UP_APIC, is this 
intended?

$ dmesg | grep -i "time\|tick\|apic"
Using tsc for high-res timesource
dyn-tick: Found suitable timer: tsc
dyn-tick: Registering dynamic tick timer v050602-2
Real Time Clock Driver v1.12
PCI: Setting latency timer of device 0000:00:1d.7 to 64
PCI: Setting latency timer of device 0000:00:1d.0 to 64
PCI: Setting latency timer of device 0000:00:1f.5 to 64
dyn-tick: Maximum ticks to skip limited to 54
dyn-tick: Timer using dynamic tick

> # for i in 1 2 3 4 5; do ntpdate -b someserver.somewhere && sleep 10; done

root@logo:~# for i in `seq 1 5`; do ntpdate ntp.uni-trier.de; sleep 60; done
 3 Jun 07:41:30 ntpdate[10348]: adjust time server 136.199.8.99 offset 
0.000522 sec
 3 Jun 07:42:30 ntpdate[10351]: adjust time server 136.199.8.99 offset 
0.000467 sec
 3 Jun 07:43:30 ntpdate[10374]: adjust time server 136.199.8.99 offset 
0.000660 sec
 3 Jun 07:44:31 ntpdate[10378]: adjust time server 136.199.8.99 offset 
0.000907 sec
 3 Jun 07:45:31 ntpdate[10406]: adjust time server 136.199.8.99 offset 
0.000653 sec

> Also, please attach your .config file too.
>
> > - pressing a key on the keyboard sometimes results in two or more
> > characters, not only one
> >
> > - mouse misses some events, e.g. clicks are not recognized (synaptics
> > touchpad)
> >
> > - using software suspend 2.1.8.10 I can suspend the system, but it hangs
> > while resuming
>
> None of this should happen...

Software suspend still does not work, it hangs on resume. Any ideas what could 
be the cause? I've applied these patches on top of 2.6.12-rc5:

2.6.12-rc4-ck1
software suspend 2.1.8.10
reiser from 2.6.12-rc5-mm1
ieee802.11 stack and ipw2100 1.1.0
hostap 0.3.7
shfs 0.35
fbsplash 0.9.2-r2
dyn-tick

Regards,
-- 
Christian

[-- Attachment #1.2: config-2.6.12-rc5+ --]
[-- Type: text/plain, Size: 34081 bytes --]

#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.12-rc5+
# Thu Jun  2 22:34:30 2005
#
CONFIG_X86=y
CONFIG_MMU=y
CONFIG_UID16=y
CONFIG_GENERIC_ISA_DMA=y
CONFIG_GENERIC_IOMAP=y

#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_INIT_ENV_ARG_LIMIT=32

#
# General setup
#
CONFIG_LOCALVERSION=""
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
CONFIG_HOTPLUG=y
# CONFIG_KOBJECT_UEVENT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
# CONFIG_EMBEDDED is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
CONFIG_CC_ALIGN_FUNCTIONS=0
CONFIG_CC_ALIGN_LABELS=0
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0

#
# Loadable module support
#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
CONFIG_OBSOLETE_MODPARM=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y

#
# Processor type and features
#
CONFIG_X86_PC=y
# CONFIG_X86_ELAN is not set
# CONFIG_X86_VOYAGER is not set
# CONFIG_X86_NUMAQ is not set
# CONFIG_X86_SUMMIT is not set
# CONFIG_X86_BIGSMP is not set
# CONFIG_X86_VISWS is not set
# CONFIG_X86_GENERICARCH is not set
# CONFIG_X86_ES7000 is not set
# CONFIG_M386 is not set
# CONFIG_M486 is not set
# CONFIG_M586 is not set
# CONFIG_M586TSC is not set
# CONFIG_M586MMX is not set
# CONFIG_M686 is not set
# CONFIG_MPENTIUMII is not set
# CONFIG_MPENTIUMIII is not set
CONFIG_MPENTIUMM=y
# CONFIG_MPENTIUM4 is not set
# CONFIG_MK6 is not set
# CONFIG_MK7 is not set
# CONFIG_MK8 is not set
# CONFIG_MCRUSOE is not set
# CONFIG_MEFFICEON is not set
# CONFIG_MWINCHIPC6 is not set
# CONFIG_MWINCHIP2 is not set
# CONFIG_MWINCHIP3D is not set
# CONFIG_MGEODEGX1 is not set
# CONFIG_MCYRIXIII is not set
# CONFIG_MVIAC3_2 is not set
# CONFIG_X86_GENERIC is not set
CONFIG_X86_CMPXCHG=y
CONFIG_X86_XADD=y
CONFIG_X86_L1_CACHE_SHIFT=6
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_X86_WP_WORKS_OK=y
CONFIG_X86_INVLPG=y
CONFIG_X86_BSWAP=y
CONFIG_X86_POPAD_OK=y
CONFIG_X86_GOOD_APIC=y
CONFIG_X86_INTEL_USERCOPY=y
CONFIG_X86_USE_PPRO_CHECKSUM=y
# CONFIG_HPET_TIMER is not set
CONFIG_NO_IDLE_HZ=y
# CONFIG_DYN_TICK_USE_APIC is not set
# CONFIG_SMP is not set
# CONFIG_PREEMPT is not set
# CONFIG_X86_UP_APIC is not set
CONFIG_X86_TSC=y
# CONFIG_X86_MCE is not set
# CONFIG_TOSHIBA is not set
# CONFIG_I8K is not set
# CONFIG_X86_REBOOTFIXUPS is not set
# CONFIG_MICROCODE is not set
# CONFIG_X86_MSR is not set
# CONFIG_X86_CPUID is not set

#
# Firmware Drivers
#
# CONFIG_EDD is not set
CONFIG_NOHIGHMEM=y
# CONFIG_HIGHMEM4G is not set
# CONFIG_HIGHMEM64G is not set
# CONFIG_1GLOWMEM is not set
# CONFIG_MATH_EMULATION is not set
CONFIG_MTRR=y
# CONFIG_EFI is not set
# CONFIG_REGPARM is not set
# CONFIG_SECCOMP is not set

#
# Power management options (ACPI, APM)
#
CONFIG_PM=y
# CONFIG_PM_DEBUG is not set
# CONFIG_SOFTWARE_SUSPEND is not set
CONFIG_SUSPEND2=y

#
# Image Storage (you need at least one writer)
#
# CONFIG_SUSPEND2_FILEWRITER is not set
CONFIG_SUSPEND2_SWAPWRITER=y

#
# Page Transformers
#
CONFIG_SUSPEND2_LZF_COMPRESSION=y

#
# User Interface Options
#
CONFIG_SUSPEND2_USERSPACE_UI=y
# CONFIG_SUSPEND2_TEXT_MODE is not set

#
# General Options
#
CONFIG_SUSPEND2_DEFAULT_RESUME2="/dev/hda7"
# CONFIG_SUSPEND2_KEEP_IMAGE is not set
CONFIG_SUSPEND2_CHECK_RESUME_SAFE=y

#
# Debugging
#
# CONFIG_SUSPEND2_DEBUG is not set

#
# ACPI (Advanced Configuration and Power Interface) Support
#
CONFIG_ACPI=y
CONFIG_ACPI_BOOT=y
CONFIG_ACPI_INTERPRETER=y
# CONFIG_ACPI_SLEEP is not set
CONFIG_ACPI_AC=y
CONFIG_ACPI_BATTERY=y
CONFIG_ACPI_BUTTON=y
CONFIG_ACPI_VIDEO=y
CONFIG_ACPI_FAN=y
CONFIG_ACPI_PROCESSOR=y
CONFIG_ACPI_THERMAL=y
# CONFIG_ACPI_ASUS is not set
# CONFIG_ACPI_IBM is not set
# CONFIG_ACPI_TOSHIBA is not set
CONFIG_ACPI_CUSTOM_DSDT=y
CONFIG_ACPI_CUSTOM_DSDT_FILE="/usr/src/source/acpi-dsdt/dsdt.hex"
CONFIG_ACPI_BLACKLIST_YEAR=0
# CONFIG_ACPI_DEBUG is not set
CONFIG_ACPI_BUS=y
CONFIG_ACPI_EC=y
CONFIG_ACPI_POWER=y
CONFIG_ACPI_PCI=y
CONFIG_ACPI_SYSTEM=y
# CONFIG_X86_PM_TIMER is not set
# CONFIG_ACPI_CONTAINER is not set

#
# APM (Advanced Power Management) BIOS Support
#
# CONFIG_APM is not set

#
# CPU Frequency scaling
#
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_TABLE=y
# CONFIG_CPU_FREQ_DEBUG is not set
# CONFIG_CPU_FREQ_STAT is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
CONFIG_CPU_FREQ_GOV_ONDEMAND=y

#
# CPUFreq processor drivers
#
# CONFIG_X86_ACPI_CPUFREQ is not set
# CONFIG_X86_POWERNOW_K6 is not set
# CONFIG_X86_POWERNOW_K7 is not set
# CONFIG_X86_POWERNOW_K8 is not set
# CONFIG_X86_GX_SUSPMOD is not set
CONFIG_X86_SPEEDSTEP_CENTRINO=y
# CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI is not set
CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y
# CONFIG_X86_SPEEDSTEP_ICH is not set
# CONFIG_X86_SPEEDSTEP_SMI is not set
# CONFIG_X86_P4_CLOCKMOD is not set
# CONFIG_X86_CPUFREQ_NFORCE2 is not set
# CONFIG_X86_LONGRUN is not set
# CONFIG_X86_LONGHAUL is not set

#
# shared options
#
# CONFIG_X86_SPEEDSTEP_LIB is not set

#
# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
#
CONFIG_PCI=y
# CONFIG_PCI_GOBIOS is not set
# CONFIG_PCI_GOMMCONFIG is not set
# CONFIG_PCI_GODIRECT is not set
CONFIG_PCI_GOANY=y
CONFIG_PCI_BIOS=y
CONFIG_PCI_DIRECT=y
CONFIG_PCI_MMCONFIG=y
# CONFIG_PCIEPORTBUS is not set
# CONFIG_PCI_LEGACY_PROC is not set
CONFIG_PCI_NAMES=y
CONFIG_ISA_DMA_API=y
# CONFIG_ISA is not set
# CONFIG_MCA is not set
# CONFIG_SCx200 is not set

#
# PCCARD (PCMCIA/CardBus) support
#
CONFIG_PCCARD=y
# CONFIG_PCMCIA_DEBUG is not set
CONFIG_PCMCIA=y
CONFIG_CARDBUS=y

#
# PC-card bridges
#
CONFIG_YENTA=y
# CONFIG_PD6729 is not set
# CONFIG_I82092 is not set
# CONFIG_TCIC is not set
CONFIG_PCCARD_NONSTATIC=y

#
# PCI Hotplug Support
#
# CONFIG_HOTPLUG_PCI is not set

#
# Executable file formats
#
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_AOUT is not set
# CONFIG_BINFMT_MISC is not set

#
# Device Drivers
#

#
# Generic Driver Options
#
# CONFIG_STANDALONE is not set
CONFIG_PREVENT_FIRMWARE_BUILD=y
CONFIG_FW_LOADER=y

#
# Memory Technology Devices (MTD)
#
# CONFIG_MTD is not set

#
# Parallel port support
#
# CONFIG_PARPORT is not set

#
# Plug and Play support
#
CONFIG_PNP=y
# CONFIG_PNP_DEBUG is not set

#
# Protocols
#
# CONFIG_PNPACPI is not set

#
# Block devices
#
# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_UMEM is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_SX8 is not set
# CONFIG_BLK_DEV_UB is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=16384
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_LBD is not set
# CONFIG_CDROM_PKTCDVD is not set

#
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
# CONFIG_IOSCHED_AS is not set
# CONFIG_IOSCHED_DEADLINE is not set
CONFIG_IOSCHED_CFQ=y
# CONFIG_ATA_OVER_ETH is not set

#
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
CONFIG_BLK_DEV_IDE=y

#
# Please see Documentation/ide.txt for help/info on IDE drives
#
# CONFIG_BLK_DEV_IDE_SATA is not set
# CONFIG_BLK_DEV_HD_IDE is not set
CONFIG_BLK_DEV_IDEDISK=y
CONFIG_IDEDISK_MULTI_MODE=y
CONFIG_BLK_DEV_IDECS=y
CONFIG_BLK_DEV_IDECD=y
# CONFIG_BLK_DEV_IDETAPE is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
# CONFIG_BLK_DEV_IDESCSI is not set
# CONFIG_IDE_TASK_IOCTL is not set

#
# IDE chipset support/bugfixes
#
# CONFIG_IDE_GENERIC is not set
# CONFIG_BLK_DEV_CMD640 is not set
# CONFIG_BLK_DEV_IDEPNP is not set
CONFIG_BLK_DEV_IDEPCI=y
# CONFIG_IDEPCI_SHARE_IRQ is not set
# CONFIG_BLK_DEV_OFFBOARD is not set
# CONFIG_BLK_DEV_GENERIC is not set
# CONFIG_BLK_DEV_OPTI621 is not set
# CONFIG_BLK_DEV_RZ1000 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
CONFIG_IDEDMA_PCI_AUTO=y
# CONFIG_IDEDMA_ONLYDISK is not set
# CONFIG_BLK_DEV_AEC62XX is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
# CONFIG_BLK_DEV_AMD74XX is not set
# CONFIG_BLK_DEV_ATIIXP is not set
# CONFIG_BLK_DEV_CMD64X is not set
# CONFIG_BLK_DEV_TRIFLEX is not set
# CONFIG_BLK_DEV_CY82C693 is not set
# CONFIG_BLK_DEV_CS5520 is not set
# CONFIG_BLK_DEV_CS5530 is not set
# CONFIG_BLK_DEV_HPT34X is not set
# CONFIG_BLK_DEV_HPT366 is not set
# CONFIG_BLK_DEV_SC1200 is not set
CONFIG_BLK_DEV_PIIX=y
# CONFIG_BLK_DEV_NS87415 is not set
# CONFIG_BLK_DEV_PDC202XX_OLD is not set
# CONFIG_BLK_DEV_PDC202XX_NEW is not set
# CONFIG_BLK_DEV_SVWKS is not set
# CONFIG_BLK_DEV_SIIMAGE is not set
# CONFIG_BLK_DEV_SIS5513 is not set
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_IVB is not set
CONFIG_IDEDMA_AUTO=y
# CONFIG_BLK_DEV_HD is not set

#
# SCSI device support
#
CONFIG_SCSI=y
# CONFIG_SCSI_PROC_FS is not set

#
# SCSI support type (disk, tape, CD-ROM)
#
CONFIG_BLK_DEV_SD=y
# CONFIG_CHR_DEV_ST is not set
# CONFIG_CHR_DEV_OSST is not set
# CONFIG_BLK_DEV_SR is not set
# CONFIG_CHR_DEV_SG is not set

#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
#
CONFIG_SCSI_MULTI_LUN=y
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set

#
# SCSI Transport Attributes
#
# CONFIG_SCSI_SPI_ATTRS is not set
# CONFIG_SCSI_FC_ATTRS is not set
# CONFIG_SCSI_ISCSI_ATTRS is not set

#
# SCSI low-level drivers
#
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AACRAID is not set
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_SCSI_SATA is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
CONFIG_SCSI_QLA2XXX=y
# CONFIG_SCSI_QLA21XX is not set
# CONFIG_SCSI_QLA22XX is not set
# CONFIG_SCSI_QLA2300 is not set
# CONFIG_SCSI_QLA2322 is not set
# CONFIG_SCSI_QLA6312 is not set
# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set

#
# PCMCIA SCSI adapter support
#
# CONFIG_PCMCIA_AHA152X is not set
# CONFIG_PCMCIA_FDOMAIN is not set
# CONFIG_PCMCIA_NINJA_SCSI is not set
# CONFIG_PCMCIA_QLOGIC is not set
# CONFIG_PCMCIA_SYM53C500 is not set

#
# Multi-device support (RAID and LVM)
#
CONFIG_MD=y
# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_DM=y
CONFIG_DM_CRYPT=y
# CONFIG_DM_SNAPSHOT is not set
# CONFIG_DM_MIRROR is not set
# CONFIG_DM_ZERO is not set
# CONFIG_DM_MULTIPATH is not set

#
# Fusion MPT device support
#
# CONFIG_FUSION is not set

#
# IEEE 1394 (FireWire) support
#
CONFIG_IEEE1394=y

#
# Subsystem Options
#
# CONFIG_IEEE1394_VERBOSEDEBUG is not set
# CONFIG_IEEE1394_OUI_DB is not set
CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
CONFIG_IEEE1394_CONFIG_ROM_IP1394=y

#
# Device Drivers
#

#
# Texas Instruments PCILynx requires I2C
#
CONFIG_IEEE1394_OHCI1394=y

#
# Protocol Drivers
#
CONFIG_IEEE1394_VIDEO1394=y
CONFIG_IEEE1394_SBP2=y
CONFIG_IEEE1394_SBP2_PHYS_DMA=y
CONFIG_IEEE1394_ETH1394=y
CONFIG_IEEE1394_DV1394=y
CONFIG_IEEE1394_RAWIO=y
# CONFIG_IEEE1394_CMP is not set

#
# I2O device support
#
# CONFIG_I2O is not set

#
# Networking support
#
CONFIG_NET=y

#
# Networking options
#
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_ARPD is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_TUNNEL is not set
# CONFIG_IP_TCPDIAG is not set
# CONFIG_IP_TCPDIAG_IPV6 is not set

#
# IP: Virtual Server Configuration
#
# CONFIG_IP_VS is not set
CONFIG_IPV6=y
# CONFIG_IPV6_PRIVACY is not set
# CONFIG_INET6_AH is not set
# CONFIG_INET6_ESP is not set
# CONFIG_INET6_IPCOMP is not set
# CONFIG_INET6_TUNNEL is not set
# CONFIG_IPV6_TUNNEL is not set
CONFIG_NETFILTER=y
# CONFIG_NETFILTER_DEBUG is not set

#
# IP: Netfilter Configuration
#
CONFIG_IP_NF_CONNTRACK=y
# CONFIG_IP_NF_CT_ACCT is not set
# CONFIG_IP_NF_CONNTRACK_MARK is not set
# CONFIG_IP_NF_CT_PROTO_SCTP is not set
CONFIG_IP_NF_FTP=y
CONFIG_IP_NF_IRC=y
# CONFIG_IP_NF_TFTP is not set
# CONFIG_IP_NF_AMANDA is not set
# CONFIG_IP_NF_QUEUE is not set
CONFIG_IP_NF_IPTABLES=y
CONFIG_IP_NF_MATCH_LIMIT=y
# CONFIG_IP_NF_MATCH_IPRANGE is not set
# CONFIG_IP_NF_MATCH_MAC is not set
CONFIG_IP_NF_MATCH_PKTTYPE=y
# CONFIG_IP_NF_MATCH_MARK is not set
# CONFIG_IP_NF_MATCH_MULTIPORT is not set
# CONFIG_IP_NF_MATCH_TOS is not set
CONFIG_IP_NF_MATCH_RECENT=y
# CONFIG_IP_NF_MATCH_ECN is not set
# CONFIG_IP_NF_MATCH_DSCP is not set
# CONFIG_IP_NF_MATCH_AH_ESP is not set
# CONFIG_IP_NF_MATCH_LENGTH is not set
# CONFIG_IP_NF_MATCH_TTL is not set
# CONFIG_IP_NF_MATCH_TCPMSS is not set
# CONFIG_IP_NF_MATCH_HELPER is not set
CONFIG_IP_NF_MATCH_STATE=y
# CONFIG_IP_NF_MATCH_CONNTRACK is not set
# CONFIG_IP_NF_MATCH_OWNER is not set
# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
# CONFIG_IP_NF_MATCH_REALM is not set
# CONFIG_IP_NF_MATCH_SCTP is not set
# CONFIG_IP_NF_MATCH_COMMENT is not set
# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
CONFIG_IP_NF_FILTER=y
CONFIG_IP_NF_TARGET_REJECT=y
CONFIG_IP_NF_TARGET_LOG=y
# CONFIG_IP_NF_TARGET_ULOG is not set
# CONFIG_IP_NF_TARGET_TCPMSS is not set
CONFIG_IP_NF_NAT=y
CONFIG_IP_NF_NAT_NEEDED=y
CONFIG_IP_NF_TARGET_MASQUERADE=y
# CONFIG_IP_NF_TARGET_REDIRECT is not set
# CONFIG_IP_NF_TARGET_NETMAP is not set
# CONFIG_IP_NF_TARGET_SAME is not set
# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
CONFIG_IP_NF_NAT_IRC=y
CONFIG_IP_NF_NAT_FTP=y
# CONFIG_IP_NF_MANGLE is not set
# CONFIG_IP_NF_RAW is not set
# CONFIG_IP_NF_ARPTABLES is not set

#
# IPv6: Netfilter Configuration (EXPERIMENTAL)
#
# CONFIG_IP6_NF_QUEUE is not set
CONFIG_IP6_NF_IPTABLES=y
CONFIG_IP6_NF_MATCH_LIMIT=y
# CONFIG_IP6_NF_MATCH_MAC is not set
# CONFIG_IP6_NF_MATCH_RT is not set
# CONFIG_IP6_NF_MATCH_OPTS is not set
# CONFIG_IP6_NF_MATCH_FRAG is not set
# CONFIG_IP6_NF_MATCH_HL is not set
# CONFIG_IP6_NF_MATCH_MULTIPORT is not set
# CONFIG_IP6_NF_MATCH_OWNER is not set
# CONFIG_IP6_NF_MATCH_MARK is not set
# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
# CONFIG_IP6_NF_MATCH_AHESP is not set
# CONFIG_IP6_NF_MATCH_LENGTH is not set
# CONFIG_IP6_NF_MATCH_EUI64 is not set
CONFIG_IP6_NF_FILTER=y
CONFIG_IP6_NF_TARGET_LOG=y
# CONFIG_IP6_NF_MANGLE is not set
# CONFIG_IP6_NF_RAW is not set

#
# SCTP Configuration (EXPERIMENTAL)
#
# CONFIG_IP_SCTP is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_DECNET is not set
# CONFIG_LLC2 is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set

#
# QoS and/or fair queueing
#
# CONFIG_NET_SCHED is not set
# CONFIG_NET_CLS_ROUTE is not set

#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
CONFIG_BT=y
CONFIG_BT_L2CAP=y
# CONFIG_BT_SCO is not set
CONFIG_BT_RFCOMM=y
CONFIG_BT_RFCOMM_TTY=y
# CONFIG_BT_BNEP is not set
# CONFIG_BT_HIDP is not set

#
# Bluetooth device drivers
#
CONFIG_BT_HCIUSB=y
# CONFIG_BT_HCIUSB_SCO is not set
# CONFIG_BT_HCIUART is not set
CONFIG_BT_HCIBCM203X=y
# CONFIG_BT_HCIBPA10X is not set
# CONFIG_BT_HCIBFUSB is not set
# CONFIG_BT_HCIDTL1 is not set
# CONFIG_BT_HCIBT3C is not set
# CONFIG_BT_HCIBLUECARD is not set
# CONFIG_BT_HCIBTUART is not set
# CONFIG_BT_HCIVHCI is not set
CONFIG_IEEE80211=y
# CONFIG_IEEE80211_DEBUG is not set
CONFIG_IEEE80211_CRYPT_WEP=y
# CONFIG_IEEE80211_CRYPT_CCMP is not set
# CONFIG_IEEE80211_CRYPT_TKIP is not set
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
CONFIG_TUN=y
# CONFIG_NET_SB1000 is not set

#
# ARCnet devices
#
# CONFIG_ARCNET is not set

#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
CONFIG_NET_VENDOR_3COM=y
CONFIG_VORTEX=y
# CONFIG_TYPHOON is not set

#
# Tulip family network device support
#
# CONFIG_NET_TULIP is not set
# CONFIG_HP100 is not set
# CONFIG_NET_PCI is not set

#
# Ethernet (1000 Mbit)
#
# CONFIG_ACENIC is not set
# CONFIG_DL2K is not set
# CONFIG_E1000 is not set
# CONFIG_NS83820 is not set
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
# CONFIG_SK98LIN is not set
# CONFIG_TIGON3 is not set

#
# Ethernet (10000 Mbit)
#
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set

#
# Token Ring devices
#
# CONFIG_TR is not set

#
# Wireless LAN (non-hamradio)
#
CONFIG_NET_RADIO=y

#
# Obsolete Wireless cards support (pre-802.11)
#
# CONFIG_STRIP is not set
# CONFIG_PCMCIA_WAVELAN is not set
# CONFIG_PCMCIA_NETWAVE is not set

#
# Wireless 802.11 Frequency Hopping cards support
#
# CONFIG_PCMCIA_RAYCS is not set

#
# Wireless 802.11b ISA/PCI cards support
#
CONFIG_IPW2100=m
CONFIG_IPW2100_PROMISC=y
# CONFIG_IPW_DEBUG is not set
# CONFIG_IPW2200 is not set
# CONFIG_HERMES is not set
# CONFIG_ATMEL is not set

#
# Wireless 802.11b Pcmcia/Cardbus cards support
#
# CONFIG_AIRO_CS is not set
# CONFIG_PCMCIA_WL3501 is not set

#
# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
#
# CONFIG_PRISM54 is not set
CONFIG_HOSTAP=y
# CONFIG_HOSTAP_FIRMWARE is not set
# CONFIG_HOSTAP_PLX is not set
# CONFIG_HOSTAP_PCI is not set
CONFIG_HOSTAP_CS=y
CONFIG_NET_WIRELESS=y

#
# PCMCIA network device support
#
# CONFIG_NET_PCMCIA is not set

#
# Wan interfaces
#
# CONFIG_WAN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
CONFIG_PPP=y
# CONFIG_PPP_MULTILINK is not set
# CONFIG_PPP_FILTER is not set
CONFIG_PPP_ASYNC=y
# CONFIG_PPP_SYNC_TTY is not set
CONFIG_PPP_DEFLATE=y
# CONFIG_PPP_BSDCOMP is not set
# CONFIG_PPPOE is not set
# CONFIG_SLIP is not set
# CONFIG_NET_FC is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set

#
# ISDN subsystem
#
# CONFIG_ISDN is not set

#
# Telephony Support
#
# CONFIG_PHONE is not set

#
# Input device support
#
CONFIG_INPUT=y

#
# Userland interfaces
#
CONFIG_INPUT_MOUSEDEV=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_TSDEV is not set
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_EVBUG is not set

#
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
CONFIG_KEYBOARD_ATKBD=y
# CONFIG_KEYBOARD_SUNKBD is not set
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
# CONFIG_MOUSE_SERIAL is not set
# CONFIG_MOUSE_VSXXXAA is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
CONFIG_INPUT_MISC=y
CONFIG_INPUT_PCSPKR=y
# CONFIG_INPUT_UINPUT is not set

#
# Hardware I/O ports
#
CONFIG_SERIO=y
CONFIG_SERIO_I8042=y
# CONFIG_SERIO_SERPORT is not set
# CONFIG_SERIO_CT82C710 is not set
# CONFIG_SERIO_PCIPS2 is not set
CONFIG_SERIO_LIBPS2=y
# CONFIG_SERIO_RAW is not set
# CONFIG_GAMEPORT is not set
CONFIG_SOUND_GAMEPORT=y

#
# Character devices
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
# CONFIG_SERIAL_NONSTANDARD is not set

#
# Serial drivers
#
# CONFIG_SERIAL_8250 is not set

#
# Non-8250 serial port support
#
# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256

#
# IPMI
#
# CONFIG_IPMI_HANDLER is not set

#
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_NVRAM is not set
CONFIG_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
# CONFIG_SONYPI is not set

#
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
# CONFIG_AGP is not set
# CONFIG_DRM is not set

#
# PCMCIA character devices
#
# CONFIG_SYNCLINK_CS is not set
# CONFIG_MWAVE is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_HPET is not set
# CONFIG_HANGCHECK_TIMER is not set

#
# TPM devices
#
# CONFIG_TCG_TPM is not set

#
# I2C support
#
# CONFIG_I2C is not set

#
# Dallas's 1-wire bus
#
# CONFIG_W1 is not set

#
# Misc devices
#
# CONFIG_IBM_ASM is not set

#
# Multimedia devices
#
CONFIG_VIDEO_DEV=y

#
# Video For Linux
#

#
# Video Adapters
#
# CONFIG_VIDEO_CPIA is not set
# CONFIG_VIDEO_STRADIS is not set
# CONFIG_VIDEO_MXB is not set
# CONFIG_VIDEO_DPC is not set
# CONFIG_VIDEO_HEXIUM_ORION is not set
# CONFIG_VIDEO_HEXIUM_GEMINI is not set

#
# Radio Adapters
#
# CONFIG_RADIO_GEMTEK_PCI is not set
# CONFIG_RADIO_MAXIRADIO is not set
# CONFIG_RADIO_MAESTRO is not set

#
# Digital Video Broadcasting Devices
#
CONFIG_DVB=y
CONFIG_DVB_CORE=y

#
# Supported SAA7146 based PCI Adapters
#
# CONFIG_DVB_AV7110 is not set
# CONFIG_DVB_BUDGET is not set
# CONFIG_DVB_BUDGET_CI is not set
# CONFIG_DVB_BUDGET_AV is not set

#
# Supported USB Adapters
#
# CONFIG_DVB_TTUSB_BUDGET is not set
# CONFIG_DVB_TTUSB_DEC is not set
# CONFIG_DVB_DIBUSB is not set
CONFIG_DVB_CINERGYT2=y
# CONFIG_DVB_CINERGYT2_TUNING is not set

#
# Supported FlexCopII (B2C2) Adapters
#
# CONFIG_DVB_B2C2_FLEXCOP is not set
# CONFIG_DVB_B2C2_SKYSTAR is not set

#
# Supported BT878 Adapters
#

#
# Supported DVB Frontends
#

#
# Customise DVB Frontends
#

#
# DVB-S (satellite) frontends
#
# CONFIG_DVB_STV0299 is not set
# CONFIG_DVB_CX24110 is not set
# CONFIG_DVB_TDA8083 is not set
# CONFIG_DVB_TDA80XX is not set
# CONFIG_DVB_MT312 is not set
# CONFIG_DVB_VES1X93 is not set

#
# DVB-T (terrestrial) frontends
#
# CONFIG_DVB_SP8870 is not set
# CONFIG_DVB_SP887X is not set
# CONFIG_DVB_CX22700 is not set
# CONFIG_DVB_CX22702 is not set
# CONFIG_DVB_L64781 is not set
# CONFIG_DVB_TDA1004X is not set
# CONFIG_DVB_NXT6000 is not set
# CONFIG_DVB_MT352 is not set
# CONFIG_DVB_DIB3000MB is not set
# CONFIG_DVB_DIB3000MC is not set

#
# DVB-C (cable) frontends
#
# CONFIG_DVB_ATMEL_AT76C651 is not set
# CONFIG_DVB_VES1820 is not set
# CONFIG_DVB_TDA10021 is not set
# CONFIG_DVB_STV0297 is not set

#
# ATSC (North American/Korean Terresterial DTV) frontends
#
# CONFIG_DVB_NXT2002 is not set
# CONFIG_DVB_OR51211 is not set
# CONFIG_DVB_OR51132 is not set

#
# Graphics support
#
CONFIG_FB=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
CONFIG_FB_SOFT_CURSOR=y
# CONFIG_FB_MACMODES is not set
CONFIG_FB_MODE_HELPERS=y
# CONFIG_FB_TILEBLITTING is not set
# CONFIG_FB_CIRRUS is not set
# CONFIG_FB_PM2 is not set
# CONFIG_FB_CYBER2000 is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_IMSTT is not set
# CONFIG_FB_VGA16 is not set
CONFIG_FB_VESA=y
CONFIG_VIDEO_SELECT=y
# CONFIG_FB_HGA is not set
# CONFIG_FB_NVIDIA is not set
# CONFIG_FB_RIVA is not set
# CONFIG_FB_I810 is not set
# CONFIG_FB_INTEL is not set
# CONFIG_FB_MATROX is not set
# CONFIG_FB_RADEON_OLD is not set
# CONFIG_FB_RADEON is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
# CONFIG_FB_SAVAGE is not set
# CONFIG_FB_SIS is not set
# CONFIG_FB_NEOMAGIC is not set
# CONFIG_FB_KYRO is not set
# CONFIG_FB_3DFX is not set
# CONFIG_FB_VOODOO1 is not set
# CONFIG_FB_TRIDENT is not set
# CONFIG_FB_GEODE is not set
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set

#
# Console display driver support
#
CONFIG_VGA_CONSOLE=y
CONFIG_DUMMY_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y
# CONFIG_FONTS is not set
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y

#
# Logo configuration
#
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
CONFIG_LOGO_LINUX_CLUT224=y
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
CONFIG_FB_SPLASH=y

#
# Sound
#
CONFIG_SOUND=y

#
# Advanced Linux Sound Architecture
#
CONFIG_SND=y
CONFIG_SND_TIMER=y
CONFIG_SND_PCM=y
CONFIG_SND_RAWMIDI=y
# CONFIG_SND_SEQUENCER is not set
# CONFIG_SND_MIXER_OSS is not set
# CONFIG_SND_PCM_OSS is not set
CONFIG_SND_RTCTIMER=y
# CONFIG_SND_VERBOSE_PRINTK is not set
# CONFIG_SND_DEBUG is not set

#
# Generic devices
#
# CONFIG_SND_DUMMY is not set
# CONFIG_SND_MTPAV is not set
# CONFIG_SND_SERIAL_U16550 is not set
# CONFIG_SND_MPU401 is not set

#
# PCI devices
#
CONFIG_SND_AC97_CODEC=y
# CONFIG_SND_ALI5451 is not set
# CONFIG_SND_ATIIXP is not set
# CONFIG_SND_ATIIXP_MODEM is not set
# CONFIG_SND_AU8810 is not set
# CONFIG_SND_AU8820 is not set
# CONFIG_SND_AU8830 is not set
# CONFIG_SND_AZT3328 is not set
# CONFIG_SND_BT87X is not set
# CONFIG_SND_CS46XX is not set
# CONFIG_SND_CS4281 is not set
# CONFIG_SND_EMU10K1 is not set
# CONFIG_SND_EMU10K1X is not set
# CONFIG_SND_CA0106 is not set
# CONFIG_SND_KORG1212 is not set
# CONFIG_SND_MIXART is not set
# CONFIG_SND_NM256 is not set
# CONFIG_SND_RME32 is not set
# CONFIG_SND_RME96 is not set
# CONFIG_SND_RME9652 is not set
# CONFIG_SND_HDSP is not set
# CONFIG_SND_TRIDENT is not set
# CONFIG_SND_YMFPCI is not set
# CONFIG_SND_ALS4000 is not set
# CONFIG_SND_CMIPCI is not set
# CONFIG_SND_ENS1370 is not set
# CONFIG_SND_ENS1371 is not set
# CONFIG_SND_ES1938 is not set
# CONFIG_SND_ES1968 is not set
# CONFIG_SND_MAESTRO3 is not set
# CONFIG_SND_FM801 is not set
# CONFIG_SND_ICE1712 is not set
# CONFIG_SND_ICE1724 is not set
CONFIG_SND_INTEL8X0=y
# CONFIG_SND_INTEL8X0M is not set
# CONFIG_SND_SONICVIBES is not set
# CONFIG_SND_VIA82XX is not set
# CONFIG_SND_VIA82XX_MODEM is not set
# CONFIG_SND_VX222 is not set
# CONFIG_SND_HDA_INTEL is not set

#
# USB devices
#
CONFIG_SND_USB_AUDIO=y
# CONFIG_SND_USB_USX2Y is not set

#
# PCMCIA devices
#

#
# Open Sound System
#
# CONFIG_SOUND_PRIME is not set

#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB=y
# CONFIG_USB_DEBUG is not set

#
# Miscellaneous USB options
#
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_BANDWIDTH is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
# CONFIG_USB_SUSPEND is not set
# CONFIG_USB_OTG is not set

#
# USB Host Controller Drivers
#
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_SPLIT_ISO is not set
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_OHCI_HCD is not set
CONFIG_USB_UHCI_HCD=y
# CONFIG_USB_SL811_HCD is not set

#
# USB Device Class drivers
#
# CONFIG_USB_AUDIO is not set

#
# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem
#
# CONFIG_USB_MIDI is not set
# CONFIG_USB_ACM is not set
# CONFIG_USB_PRINTER is not set

#
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
#
CONFIG_USB_STORAGE=y
# CONFIG_USB_STORAGE_DEBUG is not set
# CONFIG_USB_STORAGE_DATAFAB is not set
# CONFIG_USB_STORAGE_FREECOM is not set
# CONFIG_USB_STORAGE_ISD200 is not set
# CONFIG_USB_STORAGE_DPCM is not set
# CONFIG_USB_STORAGE_USBAT is not set
# CONFIG_USB_STORAGE_SDDR09 is not set
# CONFIG_USB_STORAGE_SDDR55 is not set
# CONFIG_USB_STORAGE_JUMPSHOT is not set

#
# USB Input Devices
#
CONFIG_USB_HID=y
CONFIG_USB_HIDINPUT=y
# CONFIG_HID_FF is not set
# CONFIG_USB_HIDDEV is not set
# CONFIG_USB_AIPTEK is not set
# CONFIG_USB_WACOM is not set
# CONFIG_USB_KBTAB is not set
# CONFIG_USB_POWERMATE is not set
# CONFIG_USB_MTOUCH is not set
# CONFIG_USB_EGALAX is not set
# CONFIG_USB_XPAD is not set
# CONFIG_USB_ATI_REMOTE is not set

#
# USB Imaging devices
#
# CONFIG_USB_MDC800 is not set
# CONFIG_USB_MICROTEK is not set

#
# USB Multimedia devices
#
# CONFIG_USB_DABUSB is not set
# CONFIG_USB_VICAM is not set
# CONFIG_USB_DSBR is not set
# CONFIG_USB_IBMCAM is not set
# CONFIG_USB_KONICAWC is not set
# CONFIG_USB_OV511 is not set
# CONFIG_USB_SE401 is not set
# CONFIG_USB_SN9C102 is not set
# CONFIG_USB_STV680 is not set
CONFIG_USB_PWC=y

#
# USB Network Adapters
#
# CONFIG_USB_CATC is not set
# CONFIG_USB_KAWETH is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
# CONFIG_USB_USBNET is not set
# CONFIG_USB_ZD1201 is not set
# CONFIG_USB_MON is not set

#
# USB port drivers
#

#
# USB Serial Converter support
#
# CONFIG_USB_SERIAL is not set

#
# USB Miscellaneous drivers
#
# CONFIG_USB_EMI62 is not set
# CONFIG_USB_EMI26 is not set
# CONFIG_USB_AUERSWALD is not set
# CONFIG_USB_RIO500 is not set
# CONFIG_USB_LEGOTOWER is not set
# CONFIG_USB_LCD is not set
# CONFIG_USB_LED is not set
# CONFIG_USB_CYTHERM is not set
# CONFIG_USB_PHIDGETKIT is not set
# CONFIG_USB_PHIDGETSERVO is not set
# CONFIG_USB_IDMOUSE is not set
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_TEST is not set

#
# USB ATM/DSL drivers
#

#
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set

#
# MMC/SD Card support
#
# CONFIG_MMC is not set

#
# InfiniBand support
#
# CONFIG_INFINIBAND is not set

#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
# CONFIG_EXT3_FS is not set
# CONFIG_JBD is not set
CONFIG_REISER4_FS=y
# CONFIG_REISER4_DEBUG is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set

#
# XFS support
#
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set

#
# CD-ROM/DVD Filesystems
#
CONFIG_ISO9660_FS=y
CONFIG_JOLIET=y
CONFIG_ZISOFS=y
CONFIG_ZISOFS_FS=y
CONFIG_UDF_FS=y
CONFIG_UDF_NLS=y

#
# DOS/FAT/NT Filesystems
#
CONFIG_FAT_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_FAT_DEFAULT_CODEPAGE=437
CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
# CONFIG_NTFS_FS is not set

#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
# CONFIG_DEVFS_FS is not set
# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
# CONFIG_TMPFS_XATTR is not set
# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y

#
# Miscellaneous filesystems
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_CRAMFS is not set
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_QNX4FS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set

#
# Network File Systems
#
# CONFIG_NFS_FS is not set
# CONFIG_NFSD is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
CONFIG_SH_FS=y

#
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y

#
# Native Language Support
#
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_NLS_CODEPAGE_437=y
# CONFIG_NLS_CODEPAGE_737 is not set
# CONFIG_NLS_CODEPAGE_775 is not set
CONFIG_NLS_CODEPAGE_850=y
# CONFIG_NLS_CODEPAGE_852 is not set
# CONFIG_NLS_CODEPAGE_855 is not set
# CONFIG_NLS_CODEPAGE_857 is not set
# CONFIG_NLS_CODEPAGE_860 is not set
# CONFIG_NLS_CODEPAGE_861 is not set
# CONFIG_NLS_CODEPAGE_862 is not set
# CONFIG_NLS_CODEPAGE_863 is not set
# CONFIG_NLS_CODEPAGE_864 is not set
# CONFIG_NLS_CODEPAGE_865 is not set
# CONFIG_NLS_CODEPAGE_866 is not set
# CONFIG_NLS_CODEPAGE_869 is not set
# CONFIG_NLS_CODEPAGE_936 is not set
# CONFIG_NLS_CODEPAGE_950 is not set
# CONFIG_NLS_CODEPAGE_932 is not set
# CONFIG_NLS_CODEPAGE_949 is not set
# CONFIG_NLS_CODEPAGE_874 is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_CODEPAGE_1250 is not set
# CONFIG_NLS_CODEPAGE_1251 is not set
# CONFIG_NLS_ASCII is not set
CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_ISO8859_2 is not set
# CONFIG_NLS_ISO8859_3 is not set
# CONFIG_NLS_ISO8859_4 is not set
# CONFIG_NLS_ISO8859_5 is not set
# CONFIG_NLS_ISO8859_6 is not set
# CONFIG_NLS_ISO8859_7 is not set
# CONFIG_NLS_ISO8859_9 is not set
# CONFIG_NLS_ISO8859_13 is not set
# CONFIG_NLS_ISO8859_14 is not set
CONFIG_NLS_ISO8859_15=y
# CONFIG_NLS_KOI8_R is not set
# CONFIG_NLS_KOI8_U is not set
CONFIG_NLS_UTF8=y

#
# Profiling support
#
# CONFIG_PROFILING is not set

#
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
# CONFIG_DEBUG_KERNEL is not set
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DEBUG_BUGVERBOSE=y
CONFIG_EARLY_PRINTK=y

#
# Security options
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set

#
# Cryptographic options
#
CONFIG_CRYPTO=y
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
# CONFIG_CRYPTO_MD5 is not set
# CONFIG_CRYPTO_SHA1 is not set
# CONFIG_CRYPTO_SHA256 is not set
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
# CONFIG_CRYPTO_DES is not set
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
# CONFIG_CRYPTO_SERPENT is not set
CONFIG_CRYPTO_AES_586=y
# CONFIG_CRYPTO_CAST5 is not set
# CONFIG_CRYPTO_CAST6 is not set
# CONFIG_CRYPTO_TEA is not set
CONFIG_CRYPTO_ARC4=y
# CONFIG_CRYPTO_KHAZAD is not set
# CONFIG_CRYPTO_ANUBIS is not set
# CONFIG_CRYPTO_DEFLATE is not set
# CONFIG_CRYPTO_MICHAEL_MIC is not set
# CONFIG_CRYPTO_CRC32C is not set
# CONFIG_CRYPTO_TEST is not set

#
# Hardware crypto devices
#
# CONFIG_CRYPTO_DEV_PADLOCK is not set

#
# Library routines
#
CONFIG_CRC_CCITT=y
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_LZF=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_X86_BIOS_REBOOT=y
CONFIG_PC=y

[-- Attachment #2: Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-2
  2005-06-03  6:08         ` Christian Hesse
@ 2005-06-03 17:39           ` Tony Lindgren
  2005-06-04 12:51             ` Christian Hesse
  0 siblings, 1 reply; 32+ messages in thread
From: Tony Lindgren @ 2005-06-03 17:39 UTC (permalink / raw)
  To: Christian Hesse; +Cc: linux-kernel

* Christian Hesse <mail@earthworm.de> [050602 23:09]:
> 
> The problems occured with enabled CONFIG_DYN_TICK_USE_APIC. As I recompiled 
> the kernel the following is without the option. Everything looks good so far 
> (except resume...), so I am not shure what caused the bad behavior.

OK, that's good to know.

> BTW, I can enable CONFIG_DYN_TICK_USE_APIC without CONFIG_X86_UP_APIC, is this 
> intended?

You're right, it should not be allowed. I'll make that a command
line option too for the next version.

> Software suspend still does not work, it hangs on resume. Any ideas what could 
> be the cause? I've applied these patches on top of 2.6.12-rc5:
> 
> 2.6.12-rc4-ck1
> software suspend 2.1.8.10
> reiser from 2.6.12-rc5-mm1
> ieee802.11 stack and ipw2100 1.1.0
> hostap 0.3.7
> shfs 0.35
> fbsplash 0.9.2-r2
> dyn-tick

I don't think it's the dyn-tick patch that causes it. Does the
resume work properly without the dyn-tick patch?

Tony

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-2
  2005-06-02 17:42   ` [PATCH] Dynamic tick for x86 version 050602-2 Tony Lindgren
  2005-06-02 20:03     ` Christian Hesse
@ 2005-06-03 22:37     ` Pavel Machek
  2005-06-03 22:47       ` Pavel Machek
  2005-06-10  4:17       ` Tony Lindgren
  1 sibling, 2 replies; 32+ messages in thread
From: Pavel Machek @ 2005-06-03 22:37 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: Christian Hesse, linux-kernel

Hi!

> Should be fixed now, the header was defining it as a function un UP
> system with no local apic. Can you try the following version?

Some comments below...

> @@ -102,6 +103,12 @@ fastcall unsigned int do_IRQ(struct pt_r
>  		);
>  	} else
>  #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
> +
>  		__do_IRQ(irq, regs);
>  
>  	irq_exit();

Is not indentation little wrong here?


> Index: linux-dev/arch/i386/kernel/process.c
> ===================================================================
> --- linux-dev.orig/arch/i386/kernel/process.c	2005-06-01 17:51:36.000000000 -0700
> +++ linux-dev/arch/i386/kernel/process.c	2005-06-01 17:54:32.000000000 -0700
> @@ -160,6 +161,10 @@ void cpu_idle (void)
>  			if (!idle)
>  				idle = default_idle;
>  
> +#ifdef CONFIG_NO_IDLE_HZ
> +			dyn_tick_reprogram_timer();
> +#endif
> +
>  			__get_cpu_var(irq_stat).idle_timestamp = jiffies;
>  			idle();
>  		}

Your headers are good enough; this should not be neccessary.
> +
> +#define NS_TICK_LEN		((1 * 1000000000)/HZ)
> +#define DYN_TICK_MIN_SKIP	2
> +
> +#ifdef CONFIG_NO_IDLE_HZ
> +
> +extern unsigned long dyn_tick_reprogram_timer(void);
> +
> +#else
> +
> +#define arch_has_safe_halt()		0
> +#define dyn_tick_reprogram_timer()	{}

do {} while (0)

, else you are preparing trap for someone.

> Index: linux-dev/kernel/dyn-tick.c
> ===================================================================
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ linux-dev/kernel/dyn-tick.c	2005-06-02 10:37:12.000000000 -0700
> @@ -0,0 +1,235 @@
> +/*
> + * linux/arch/i386/kernel/dyn-tick.c
> + *
> + * Beginnings of generic dynamic tick timer support
> + *
> + * Copyright (C) 2004 Nokia Corporation
> + * Written by Tony Lindgen <tony@atomide.com> and
> + * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
> + *

Heh, you work for Nokia? Can I get one of those nokia 770 toys? I
should have 100 euros somewhere here :-).
								Pavel


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-2
  2005-06-03 22:37     ` Pavel Machek
@ 2005-06-03 22:47       ` Pavel Machek
  2005-06-10  4:17       ` Tony Lindgren
  1 sibling, 0 replies; 32+ messages in thread
From: Pavel Machek @ 2005-06-03 22:47 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: Christian Hesse, linux-kernel

Hi!

> > Should be fixed now, the header was defining it as a function un UP
> > system with no local apic. Can you try the following version?
> 
> Some comments below...

Seems to work okay here. Even with CONFIG_DYN_TICK_USE_APIC=y.

								Pavel

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-2
  2005-06-03 17:39           ` Tony Lindgren
@ 2005-06-04 12:51             ` Christian Hesse
  2005-06-10  4:03               ` Tony Lindgren
  0 siblings, 1 reply; 32+ messages in thread
From: Christian Hesse @ 2005-06-04 12:51 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 811 bytes --]

On Friday 03 June 2005 19:39, Tony Lindgren wrote:
[ ... ]
> > Software suspend still does not work, it hangs on resume. Any ideas what
> > could be the cause? I've applied these patches on top of 2.6.12-rc5:
> >
> > 2.6.12-rc4-ck1
> > software suspend 2.1.8.10
> > reiser from 2.6.12-rc5-mm1
> > ieee802.11 stack and ipw2100 1.1.0
> > hostap 0.3.7
> > shfs 0.35
> > fbsplash 0.9.2-r2
> > dyn-tick
>
> I don't think it's the dyn-tick patch that causes it. Does the
> resume work properly without the dyn-tick patch?

I've simply disabled CONFIG_NO_IDLE_HZ, recompiled the kernel and resume works 
perfectly.

But I found another drawback. ping -f reports lots of these errors (though it 
still works):

Warning: time of day goes back (0.122us), taking countermeasures.

-- 
Christian

[-- Attachment #2: Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-2
  2005-06-02 20:03     ` Christian Hesse
  2005-06-02 20:32       ` Tony Lindgren
@ 2005-06-05  4:06       ` Bernard Blackham
  2005-06-10  4:05         ` Tony Lindgren
  1 sibling, 1 reply; 32+ messages in thread
From: Bernard Blackham @ 2005-06-05  4:06 UTC (permalink / raw)
  To: Christian Hesse; +Cc: Tony Lindgren, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1959 bytes --]

On Thu, Jun 02, 2005 at 10:03:18PM +0200, Christian Hesse wrote:
> > > > Please let me know of any issues with the patch. I'll continue to do
> > > > more clean-up on it, but I think the basic functionality is done.

If CONFIG_NO_IDLE_HZ and CONFIG_X86_UP_APIC is set, but
CONFIG_DYN_TICK_USE_APIC is *not* set, there's still one case where
reprogram_apic_timer was still being called. This was causing my system
to seize for around a second or so when doing some things (most notably
probing for devices on boot, and when suspending/resuming PCI devices).
Attached patch fixes those hangs for me.

However, "using APIC" is still reported as 1 in sysfs. This is cosmetic,
but still incorrect :)

> - using software suspend 2.1.8.10 I can suspend the system, but it
>   hangs while resuming

When software suspend resumes, it suspends (more correctly, "freezes")
all devices, copies the old kernel over the top of itself with
interrupts off (which includes the value of xtime from suspend-time),
and then resumes all devices.  The resuming all devices bit includes
calling timer_resume in arch/i386/kernel/time.c which winds xtime
forwards by the amount of time we were asleep for (according to the CMOS
clock). I think this may be one source of confusion to the dyntick code.

Turning on dyn_tick_dbg and some extra printk's shows that it hangs
inside this loop in dyn_tick_timer_interrupt:

    while (now - last_tick >= NS_TICK_LEN) {
		last_tick += NS_TICK_LEN;
		[... call do_timer_interrupt and stuff ... ]
	}

I haven't pinned it down yet, but I'm curious if perhaps now <
last_tick, in which case the loop will take until the end of the
universe to terminate (well, nearly). There's reference in timer_tsc.c
to APM doing magic to ensure monotonic_clock is infact monotonic when
suspending to disk (as the TSC counter itself will get reset to zero on
boot), but I'm not sure what this magic is, or if the magic is done if
we're not using APM.

Bernard.

[-- Attachment #2: dyntick-fixes-brb-1.diff --]
[-- Type: text/plain, Size: 499 bytes --]

Index: linux/kernel/dyn-tick.c
===================================================================
--- linux.orig/kernel/dyn-tick.c	2005-06-05 00:51:53.000000000 +0800
+++ linux/kernel/dyn-tick.c	2005-06-05 01:02:55.000000000 +0800
@@ -54,7 +54,8 @@
 
 	/* Check if we are already skipping ticks and can idle other cpus */
 	if (dyn_tick->state & DYN_TICK_SKIPPING) {
-		reprogram_apic_timer(dyn_tick->skip);
+		if (cpu_has_local_apic())
+			reprogram_apic_timer(dyn_tick->skip);
 		return 0;
 	}
 

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-1
  2005-06-02  1:36 [PATCH] Dynamic tick for x86 version 050602-1 Tony Lindgren
  2005-06-02  1:54 ` Zwane Mwaikambo
  2005-06-02  8:30 ` Christian Hesse
@ 2005-06-07 20:36 ` Jonathan Corbet
  2005-06-10  4:18   ` Tony Lindgren
  2 siblings, 1 reply; 32+ messages in thread
From: Jonathan Corbet @ 2005-06-07 20:36 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-kernel

Tony Lindgren <tony@atomide.com> wrote:

> --- linux-dev.orig/arch/i386/kernel/irq.c	2005-06-01 17:51:36.000000000 -0700
> +++ linux-dev/arch/i386/kernel/irq.c	2005-06-01 17:54:32.000000000 -0700
> [...]
> @@ -102,6 +103,12 @@ fastcall unsigned int do_IRQ(struct pt_r
>  		);
>  	} else
>  #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
> +
>  		__do_IRQ(irq, regs);

Forgive me if I'm being obtuse (again...), but this hunk doesn't look
like it would work well in the 4K stacks case.  When 4K stacks are being
used, dyn_tick->interrupt() will only get called in the nested interrupt
case, when the interrupt stack is already in use.  This change also
pushes the non-assembly __do_IRQ() call out of the else branch, meaning
that, when the switch is made to the interrupt stack (most of the time),
__do_IRQ() will be called twice for the same interrupt.

It looks to me like you want to put your #ifdef chunk *after* the call
to __do_IRQ(), unless you have some reason for needing it to happen
before the regular interrupt handler is invoked.

What am I missing?

jon

Jonathan Corbet
Executive editor, LWN.net
corbet@lwn.net

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-2
  2005-06-04 12:51             ` Christian Hesse
@ 2005-06-10  4:03               ` Tony Lindgren
  0 siblings, 0 replies; 32+ messages in thread
From: Tony Lindgren @ 2005-06-10  4:03 UTC (permalink / raw)
  To: Christian Hesse; +Cc: linux-kernel

* Christian Hesse <mail@earthworm.de> [050604 05:51]:
> On Friday 03 June 2005 19:39, Tony Lindgren wrote:
> [ ... ]
> > > Software suspend still does not work, it hangs on resume. Any ideas what
> > > could be the cause? I've applied these patches on top of 2.6.12-rc5:
> > >
> > > 2.6.12-rc4-ck1
> > > software suspend 2.1.8.10
> > > reiser from 2.6.12-rc5-mm1
> > > ieee802.11 stack and ipw2100 1.1.0
> > > hostap 0.3.7
> > > shfs 0.35
> > > fbsplash 0.9.2-r2
> > > dyn-tick
> >
> > I don't think it's the dyn-tick patch that causes it. Does the
> > resume work properly without the dyn-tick patch?
> 
> I've simply disabled CONFIG_NO_IDLE_HZ, recompiled the kernel and resume works 
> perfectly.

Weird, it suspend and resume works fine for me. Or worked on my small laptop
until I fried it's mobo few days ago...

> But I found another drawback. ping -f reports lots of these errors (though it 
> still works):
> 
> Warning: time of day goes back (0.122us), taking countermeasures.

I haven't seen this one either. Maybe try the patch I'll post shortly.

Tony

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-2
  2005-06-05  4:06       ` Bernard Blackham
@ 2005-06-10  4:05         ` Tony Lindgren
  0 siblings, 0 replies; 32+ messages in thread
From: Tony Lindgren @ 2005-06-10  4:05 UTC (permalink / raw)
  To: Bernard Blackham; +Cc: Christian Hesse, linux-kernel

* Bernard Blackham <b-lkml@blackham.com.au> [050604 21:07]:
> On Thu, Jun 02, 2005 at 10:03:18PM +0200, Christian Hesse wrote:
> > > > > Please let me know of any issues with the patch. I'll continue to do
> > > > > more clean-up on it, but I think the basic functionality is done.
> 
> If CONFIG_NO_IDLE_HZ and CONFIG_X86_UP_APIC is set, but
> CONFIG_DYN_TICK_USE_APIC is *not* set, there's still one case where
> reprogram_apic_timer was still being called. This was causing my system
> to seize for around a second or so when doing some things (most notably
> probing for devices on boot, and when suspending/resuming PCI devices).
> Attached patch fixes those hangs for me.

Thanks, I've added it to the patch I'll post shortly.

> However, "using APIC" is still reported as 1 in sysfs. This is cosmetic,
> but still incorrect :)

Urhg, yes it still needs some cleaning up...

> > - using software suspend 2.1.8.10 I can suspend the system, but it
> >   hangs while resuming
> 
> When software suspend resumes, it suspends (more correctly, "freezes")
> all devices, copies the old kernel over the top of itself with
> interrupts off (which includes the value of xtime from suspend-time),
> and then resumes all devices.  The resuming all devices bit includes
> calling timer_resume in arch/i386/kernel/time.c which winds xtime
> forwards by the amount of time we were asleep for (according to the CMOS
> clock). I think this may be one source of confusion to the dyntick code.
> 
> Turning on dyn_tick_dbg and some extra printk's shows that it hangs
> inside this loop in dyn_tick_timer_interrupt:
> 
>     while (now - last_tick >= NS_TICK_LEN) {
> 		last_tick += NS_TICK_LEN;
> 		[... call do_timer_interrupt and stuff ... ]
> 	}
> 
> I haven't pinned it down yet, but I'm curious if perhaps now <
> last_tick, in which case the loop will take until the end of the
> universe to terminate (well, nearly). There's reference in timer_tsc.c
> to APM doing magic to ensure monotonic_clock is infact monotonic when
> suspending to disk (as the TSC counter itself will get reset to zero on
> boot), but I'm not sure what this magic is, or if the magic is done if
> we're not using APM.

Again, it suspend and resume worked fine on my laptop. No APIC timer on it
though.

Tony

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-2
  2005-06-03 22:37     ` Pavel Machek
  2005-06-03 22:47       ` Pavel Machek
@ 2005-06-10  4:17       ` Tony Lindgren
  2005-06-10  9:15         ` Pavel Machek
  1 sibling, 1 reply; 32+ messages in thread
From: Tony Lindgren @ 2005-06-10  4:17 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Christian Hesse, linux-kernel

* Pavel Machek <pavel@ucw.cz> [050603 15:38]:
> Hi!
> 
> > Should be fixed now, the header was defining it as a function un UP
> > system with no local apic. Can you try the following version?
> 
> Some comments below...
> 
> > @@ -102,6 +103,12 @@ fastcall unsigned int do_IRQ(struct pt_r
> >  		);
> >  	} else
> >  #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
> > +
> >  		__do_IRQ(irq, regs);
> >  
> >  	irq_exit();
> 
> Is not indentation little wrong here?

Good catch, this is fixed now.

> > Index: linux-dev/arch/i386/kernel/process.c
> > ===================================================================
> > --- linux-dev.orig/arch/i386/kernel/process.c	2005-06-01 17:51:36.000000000 -0700
> > +++ linux-dev/arch/i386/kernel/process.c	2005-06-01 17:54:32.000000000 -0700
> > @@ -160,6 +161,10 @@ void cpu_idle (void)
> >  			if (!idle)
> >  				idle = default_idle;
> >  
> > +#ifdef CONFIG_NO_IDLE_HZ
> > +			dyn_tick_reprogram_timer();
> > +#endif
> > +
> >  			__get_cpu_var(irq_stat).idle_timestamp = jiffies;
> >  			idle();
> >  		}
> 
> Your headers are good enough; this should not be neccessary.

Great, one ifdef less :)

> > +#define NS_TICK_LEN		((1 * 1000000000)/HZ)
> > +#define DYN_TICK_MIN_SKIP	2
> > +
> > +#ifdef CONFIG_NO_IDLE_HZ
> > +
> > +extern unsigned long dyn_tick_reprogram_timer(void);
> > +
> > +#else
> > +
> > +#define arch_has_safe_halt()		0
> > +#define dyn_tick_reprogram_timer()	{}
> 
> do {} while (0)
> 
> , else you are preparing trap for someone.

Can you please explain what the difference between these two are?
Some compiler version specific thing?

> > Index: linux-dev/kernel/dyn-tick.c
> > ===================================================================
> > --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> > +++ linux-dev/kernel/dyn-tick.c	2005-06-02 10:37:12.000000000 -0700
> > @@ -0,0 +1,235 @@
> > +/*
> > + * linux/arch/i386/kernel/dyn-tick.c
> > + *
> > + * Beginnings of generic dynamic tick timer support
> > + *
> > + * Copyright (C) 2004 Nokia Corporation
> > + * Written by Tony Lindgen <tony@atomide.com> and
> > + * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
> > + *
> 
> Heh, you work for Nokia? Can I get one of those nokia 770 toys? I
> should have 100 euros somewhere here :-).

Yes, we did dyntick originally for ARM OMAP and 770. I don't think
I have any power who Nokia will be giving the discount developer
770's for though :) I think you have to apply on some webpage...
Naturally you can try to use me as a reference, but I don't know
if it helps :)

Cheers,

Tony

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-1
  2005-06-07 20:36 ` [PATCH] Dynamic tick for x86 version 050602-1 Jonathan Corbet
@ 2005-06-10  4:18   ` Tony Lindgren
  0 siblings, 0 replies; 32+ messages in thread
From: Tony Lindgren @ 2005-06-10  4:18 UTC (permalink / raw)
  To: Jonathan Corbet; +Cc: linux-kernel

* Jonathan Corbet <corbet@lwn.net> [050607 13:36]:
> Tony Lindgren <tony@atomide.com> wrote:
> 
> > --- linux-dev.orig/arch/i386/kernel/irq.c	2005-06-01 17:51:36.000000000 -0700
> > +++ linux-dev/arch/i386/kernel/irq.c	2005-06-01 17:54:32.000000000 -0700
> > [...]
> > @@ -102,6 +103,12 @@ fastcall unsigned int do_IRQ(struct pt_r
> >  		);
> >  	} else
> >  #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
> > +
> >  		__do_IRQ(irq, regs);
> 
> Forgive me if I'm being obtuse (again...), but this hunk doesn't look
> like it would work well in the 4K stacks case.  When 4K stacks are being
> used, dyn_tick->interrupt() will only get called in the nested interrupt
> case, when the interrupt stack is already in use.  This change also
> pushes the non-assembly __do_IRQ() call out of the else branch, meaning
> that, when the switch is made to the interrupt stack (most of the time),
> __do_IRQ() will be called twice for the same interrupt.

Good catch as mentioned earlier :)

> It looks to me like you want to put your #ifdef chunk *after* the call
> to __do_IRQ(), unless you have some reason for needing it to happen
> before the regular interrupt handler is invoked.

Time needs to be updated before __do_IRQ() so interrupt handlers have
correct time.

Tony

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-2
  2005-06-10  4:17       ` Tony Lindgren
@ 2005-06-10  9:15         ` Pavel Machek
  2005-06-10 15:17           ` Tony Lindgren
  2005-06-11 17:59           ` [PATCH] Dynamic tick for x86 version 050602-2 Kyle Moffett
  0 siblings, 2 replies; 32+ messages in thread
From: Pavel Machek @ 2005-06-10  9:15 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: Christian Hesse, linux-kernel

Hi!

> > > +#define NS_TICK_LEN		((1 * 1000000000)/HZ)
> > > +#define DYN_TICK_MIN_SKIP	2
> > > +
> > > +#ifdef CONFIG_NO_IDLE_HZ
> > > +
> > > +extern unsigned long dyn_tick_reprogram_timer(void);
> > > +
> > > +#else
> > > +
> > > +#define arch_has_safe_halt()		0
> > > +#define dyn_tick_reprogram_timer()	{}
> > 
> > do {} while (0)
> > 
> > , else you are preparing trap for someone.
> 
> Can you please explain what the difference between these two are?
> Some compiler version specific thing?

It took me quite some remembering. Problem is that with your macros,
someone can write

	dyn_tick_reprogram_timer()
	printk();

[notice missing ; at first line], and still get it compile. If you
replace {} with do {} while (0), he'll get compile error as he should.

> > > Index: linux-dev/kernel/dyn-tick.c
> > > ===================================================================
> > > --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> > > +++ linux-dev/kernel/dyn-tick.c	2005-06-02 10:37:12.000000000 -0700
> > > @@ -0,0 +1,235 @@
> > > +/*
> > > + * linux/arch/i386/kernel/dyn-tick.c
> > > + *
> > > + * Beginnings of generic dynamic tick timer support
> > > + *
> > > + * Copyright (C) 2004 Nokia Corporation
> > > + * Written by Tony Lindgen <tony@atomide.com> and
> > > + * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
> > > + *
> > 
> > Heh, you work for Nokia? Can I get one of those nokia 770 toys? I
> > should have 100 euros somewhere here :-).
> 
> Yes, we did dyntick originally for ARM OMAP and 770. I don't think
> I have any power who Nokia will be giving the discount developer
> 770's for though :) I think you have to apply on some webpage...

Thanks for the info (and for the ARM work).
								Pavel 

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-2
  2005-06-10  9:15         ` Pavel Machek
@ 2005-06-10 15:17           ` Tony Lindgren
  2005-06-10 22:15             ` [PATCH] Dynamic tick for x86 version 050610-1 Tony Lindgren
  2005-06-11 17:59           ` [PATCH] Dynamic tick for x86 version 050602-2 Kyle Moffett
  1 sibling, 1 reply; 32+ messages in thread
From: Tony Lindgren @ 2005-06-10 15:17 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Christian Hesse, linux-kernel

* Pavel Machek <pavel@ucw.cz> [050610 02:15]:
> Hi!
> 
> > > > +#define NS_TICK_LEN		((1 * 1000000000)/HZ)
> > > > +#define DYN_TICK_MIN_SKIP	2
> > > > +
> > > > +#ifdef CONFIG_NO_IDLE_HZ
> > > > +
> > > > +extern unsigned long dyn_tick_reprogram_timer(void);
> > > > +
> > > > +#else
> > > > +
> > > > +#define arch_has_safe_halt()		0
> > > > +#define dyn_tick_reprogram_timer()	{}
> > > 
> > > do {} while (0)
> > > 
> > > , else you are preparing trap for someone.
> > 
> > Can you please explain what the difference between these two are?
> > Some compiler version specific thing?
> 
> It took me quite some remembering. Problem is that with your macros,
> someone can write
> 
> 	dyn_tick_reprogram_timer()
> 	printk();
> 
> [notice missing ; at first line], and still get it compile. If you
> replace {} with do {} while (0), he'll get compile error as he should.

Thanks for clarifying, I'll change it.

Tony

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH] Dynamic tick for x86 version 050610-1
  2005-06-10 15:17           ` Tony Lindgren
@ 2005-06-10 22:15             ` Tony Lindgren
  2005-06-18  3:34               ` hugang
  0 siblings, 1 reply; 32+ messages in thread
From: Tony Lindgren @ 2005-06-10 22:15 UTC (permalink / raw)
  To: linux-kernel
  Cc: Pallipadi, Venkatesh, Jonathan Corbet, Pavel Machek,
	Bernard Blackham, Christian Hesse, Zwane Mwaikambo

[-- Attachment #1: Type: text/plain, Size: 231 bytes --]

Hi all,

Here's yet another version with more clean-up:

- Got rid of ifdefs for skipping timer calibration; Skipping is
  now done based on dyn_tick_enaled() instead.

- Clean-up fixes as suggested by Pavel Machek.

Cheers,

Tony

[-- Attachment #2: patch-dynamic-tick-2.6.12-rc6-050610-1 --]
[-- Type: text/plain, Size: 24679 bytes --]

Index: linux-dev/arch/i386/Kconfig
===================================================================
--- linux-dev.orig/arch/i386/Kconfig	2005-06-10 10:34:42.000000000 -0700
+++ linux-dev/arch/i386/Kconfig	2005-06-10 11:39:09.000000000 -0700
@@ -458,6 +458,38 @@
 	bool "Provide RTC interrupt"
 	depends on HPET_TIMER && RTC=y
 
+config NO_IDLE_HZ
+	bool "Dynamic Tick Timer - Skip timer ticks during idle"
+	help
+	  This option enables support for skipping timer ticks when the
+	  processor is idle. During system load, timer is continuous.
+	  This option saves power, as it allows the system to stay in
+	  idle mode longer. Currently supported timers are ACPI PM
+	  timer, local APIC timer, and TSC timer. HPET timer is currently
+	  not supported.
+
+	  Note that you need to enable dynamic tick timer either by
+	  passing dyntick=enable command line option, or via sysfs:
+
+	  # echo 1 > /sys/devices/system/timer/timer0/dyn_tick_state
+
+config DYN_TICK_USE_APIC
+	bool "Use APIC timer instead of PIT timer"
+	depends on NO_IDLE_HZ
+	help
+	  This option enables using APIC timer interrupt if your hardware
+	  supports it. APIC timer allows longer sleep periods compared
+	  to PIT timer.
+
+	  Note that on most recent hardware disabling PIT timer also
+	  disables APIC timer interrupts, and system won't run properly.
+	  Symptoms include slow system boot, and time running slow.
+
+	  If unsure, don't enable this option.
+
+	  Note that to you still need to pass dyntick=enable,forceapic
+	  command line option to use APIC timer.
+
 config SMP
 	bool "Symmetric multi-processing support"
 	---help---
Index: linux-dev/arch/i386/kernel/Makefile
===================================================================
--- linux-dev.orig/arch/i386/kernel/Makefile	2005-06-10 10:34:42.000000000 -0700
+++ linux-dev/arch/i386/kernel/Makefile	2005-06-10 10:36:12.000000000 -0700
@@ -31,6 +31,7 @@
 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-$(CONFIG_EFI) 		+= efi.o efi_stub.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 
Index: linux-dev/arch/i386/kernel/apic.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/apic.c	2005-06-10 10:34:42.000000000 -0700
+++ linux-dev/arch/i386/kernel/apic.c	2005-06-10 10:36:12.000000000 -0700
@@ -26,6 +26,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/kernel_stat.h>
 #include <linux/sysdev.h>
+#include <linux/dyn-tick.h>
 
 #include <asm/atomic.h>
 #include <asm/smp.h>
@@ -909,6 +910,8 @@
 
 #define APIC_DIVISOR 16
 
+static u32 apic_timer_val;
+
 static void __setup_APIC_LVTT(unsigned int clocks)
 {
 	unsigned int lvtt_value, tmp_value, ver;
@@ -927,7 +930,15 @@
 				& ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
 				| APIC_TDR_DIV_16);
 
-	apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR);
+	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
+
+	apic_write_around(APIC_TMICT, apic_timer_val);
 }
 
 static void __init setup_APIC_timer(unsigned int clocks)
@@ -1040,6 +1051,13 @@
 	 */
 	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
+
 	local_irq_enable();
 }
 
@@ -1068,6 +1086,18 @@
 	}
 }
 
+#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.
@@ -1160,6 +1190,7 @@
 
 fastcall void smp_apic_timer_interrupt(struct pt_regs *regs)
 {
+	unsigned long seq;
 	int cpu = smp_processor_id();
 
 	/*
@@ -1178,6 +1209,23 @@
 	 * interrupt lock, which is the WrongThing (tm) to do.
 	 */
 	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
+
 	smp_local_timer_interrupt(regs);
 	irq_exit();
 }
Index: linux-dev/arch/i386/kernel/dyn-tick.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-dev/arch/i386/kernel/dyn-tick.c	2005-06-10 10:36:12.000000000 -0700
@@ -0,0 +1,45 @@
+/*
+ * linux/arch/i386/kernel/dyn-tick.c
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Tony Lindgen <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.
+ */
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/dyn-tick.h>
+
+void arch_reprogram_timer(void)
+{
+	if (cpu_has_local_apic()) {
+		disable_pit_timer();
+		if (dyn_tick->state & DYN_TICK_TIMER_INT)
+			reprogram_apic_timer(dyn_tick->skip);
+	} else {
+		if (dyn_tick->state & DYN_TICK_TIMER_INT)
+			reprogram_pit_timer(dyn_tick->skip);
+		else
+			disable_pit_timer();
+	}
+}
+
+static struct dyn_tick_timer arch_dyn_tick_timer = {
+	.arch_reprogram_timer	= &arch_reprogram_timer,
+};
+
+int __init dyn_tick_init(void)
+{
+	arch_dyn_tick_timer.arch_init = dyn_tick_arch_init;
+	dyn_tick_register(&arch_dyn_tick_timer);
+
+	return 0;
+}
+arch_initcall(dyn_tick_init);
Index: linux-dev/include/asm-i386/dyn-tick.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-dev/include/asm-i386/dyn-tick.h	2005-06-10 10:36:12.000000000 -0700
@@ -0,0 +1,34 @@
+/*
+ * linux/include/asm-i386/dyn-tick.h
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Tony Lindgen <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.
+ */
+
+#ifndef _ASM_I386_DYN_TICK_H_
+#define _ASM_I386_DYN_TICK_H_
+
+extern int dyn_tick_arch_init(void);
+extern void disable_pit_timer(void);
+extern void reprogram_pit_timer(int jiffies_to_skip);
+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)
+#else
+#define cpu_has_local_apic()	0
+#endif
+
+#endif /* _ASM_I386_DYN_TICK_H_ */
Index: linux-dev/arch/i386/kernel/irq.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/irq.c	2005-06-10 10:34:42.000000000 -0700
+++ linux-dev/arch/i386/kernel/irq.c	2005-06-10 10:36:12.000000000 -0700
@@ -15,6 +15,7 @@
 #include <linux/seq_file.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
+#include <linux/dyn-tick.h>
 
 DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_maxaligned_in_smp;
 EXPORT_PER_CPU_SYMBOL(irq_stat);
@@ -73,6 +74,11 @@
 	}
 #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
+
 #ifdef CONFIG_4KSTACKS
 
 	curctx = (union irq_ctx *) current_thread_info();
Index: linux-dev/arch/i386/kernel/process.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/process.c	2005-06-10 10:34:42.000000000 -0700
+++ linux-dev/arch/i386/kernel/process.c	2005-06-10 10:36:12.000000000 -0700
@@ -37,6 +37,7 @@
 #include <linux/kallsyms.h>
 #include <linux/ptrace.h>
 #include <linux/random.h>
+#include <linux/dyn-tick.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -160,6 +161,8 @@
 			if (!idle)
 				idle = default_idle;
 
+			dyn_tick_reprogram_timer();
+
 			__get_cpu_var(irq_stat).idle_timestamp = jiffies;
 			idle();
 		}
Index: linux-dev/arch/i386/kernel/time.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/time.c	2005-06-10 10:34:42.000000000 -0700
+++ linux-dev/arch/i386/kernel/time.c	2005-06-10 11:35:31.000000000 -0700
@@ -46,6 +46,7 @@
 #include <linux/bcd.h>
 #include <linux/efi.h>
 #include <linux/mca.h>
+#include <linux/dyn-tick.h>
 
 #include <asm/io.h>
 #include <asm/smp.h>
@@ -308,6 +309,43 @@
 	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)
 {
@@ -416,7 +454,7 @@
 
 
 /* XXX this driverfs stuff should probably go elsewhere later -john */
-static struct sys_device device_timer = {
+struct sys_device device_timer = {
 	.id	= 0,
 	.cls	= &timer_sysclass,
 };
@@ -452,6 +490,28 @@
 }
 #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
@@ -472,5 +532,16 @@
 	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
+
 	time_init_hook();
 }
Index: linux-dev/arch/i386/kernel/timers/timer_pm.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/timers/timer_pm.c	2005-06-10 10:34:42.000000000 -0700
+++ linux-dev/arch/i386/kernel/timers/timer_pm.c	2005-06-10 11:47:30.000000000 -0700
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/init.h>
+#include <linux/dyn-tick.h>
 #include <asm/types.h>
 #include <asm/timer.h>
 #include <asm/smp.h>
@@ -168,6 +169,9 @@
 	monotonic_base += delta * NSEC_PER_USEC;
 	write_sequnlock(&monotonic_lock);
 
+	if (dyn_tick_enabled())
+		return;
+
 	/* convert to ticks */
 	delta += offset_delay;
 	lost = delta / (USEC_PER_SEC / HZ);
Index: linux-dev/arch/i386/kernel/timers/timer_tsc.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/timers/timer_tsc.c	2005-06-10 10:34:42.000000000 -0700
+++ linux-dev/arch/i386/kernel/timers/timer_tsc.c	2005-06-10 11:53:04.000000000 -0700
@@ -14,6 +14,7 @@
 #include <linux/cpufreq.h>
 #include <linux/string.h>
 #include <linux/jiffies.h>
+#include <linux/dyn-tick.h>
 
 #include <asm/timer.h>
 #include <asm/io.h>
@@ -368,6 +369,9 @@
 
 	rdtsc(last_tsc_low, last_tsc_high);
 
+	if (dyn_tick_enabled())
+		goto monotonic_base;
+
 	spin_lock(&i8253_lock);
 	outb_p(0x00, PIT_MODE);     /* latch the count ASAP */
 
@@ -435,11 +439,17 @@
 			cpufreq_delayed_get();
 	} else
 		lost_count = 0;
+
+ monotonic_base:
+
 	/* update the monotonic base value */
 	this_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
 	monotonic_base += cycles_2_ns(this_offset - last_offset);
 	write_sequnlock(&monotonic_lock);
 
+	if (dyn_tick_enabled())
+		return;
+
 	/* calculate delay_at_last_interrupt */
 	count = ((LATCH-1) - count) * TICK_SIZE;
 	delay_at_last_interrupt = (count + LATCH/2) / LATCH;
Index: linux-dev/arch/i386/mach-default/setup.c
===================================================================
--- linux-dev.orig/arch/i386/mach-default/setup.c	2005-06-10 10:34:42.000000000 -0700
+++ linux-dev/arch/i386/mach-default/setup.c	2005-06-10 10:36:12.000000000 -0700
@@ -85,6 +85,22 @@
 	setup_irq(0, &irq0);
 }
 
+/**
+ * replace_timer_interrupt - allow replacing timer interrupt handler
+ *
+ * Description:
+ *	Can be used to replace timer interrupt handler with a more optimized
+ *	handler. Used for enabling and disabling of CONFIG_NO_IDLE_HZ.
+ */
+void replace_timer_interrupt(void * new_handler)
+{
+	unsigned long flags;
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+	irq0.handler = new_handler;
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+}
+
 #ifdef CONFIG_MCA
 /**
  * mca_nmi_hook - hook into MCA specific NMI chain
Index: linux-dev/include/linux/dyn-tick.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-dev/include/linux/dyn-tick.h	2005-06-10 11:48:08.000000000 -0700
@@ -0,0 +1,64 @@
+/*
+ * linux/include/linux/dyn-tick.h
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Tony Lindgen <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.
+ */
+
+#ifndef _DYN_TICK_TIMER_H
+#define _DYN_TICK_TIMER_H
+
+#include <linux/interrupt.h>
+
+#define DYN_TICK_TIMER_INT	(1 << 4)
+#define DYN_TICK_USE_APIC	(1 << 3)
+#define DYN_TICK_SKIPPING	(1 << 2)
+#define DYN_TICK_ENABLED	(1 << 1)
+#define DYN_TICK_SUITABLE	(1 << 0)
+
+struct dyn_tick_state {
+	unsigned int state;		/* Current state */
+	int skip_cpu;			/* Skip handling processor */
+	unsigned long skip;		/* Ticks to skip */
+	unsigned int max_skip;		/* Max number of ticks to skip */
+	unsigned long irq_skip_mask;	/* Do not update time from these irqs */
+	irqreturn_t (*interrupt)(int, void *, struct pt_regs *);
+};
+
+struct dyn_tick_timer {
+	int (*arch_init) (void);
+	void (*arch_enable) (void);
+	void (*arch_disable) (void);
+	void (*arch_reprogram_timer) (void);
+};
+
+extern struct dyn_tick_state * dyn_tick;
+extern void dyn_tick_register(struct dyn_tick_timer * new_timer);
+
+#define NS_TICK_LEN		((1 * 1000000000)/HZ)
+#define DYN_TICK_MIN_SKIP	2
+
+
+#ifdef CONFIG_NO_IDLE_HZ
+
+extern unsigned long dyn_tick_reprogram_timer(void);
+#define dyn_tick_enabled()		(dyn_tick->state & DYN_TICK_ENABLED)
+
+#else
+
+#define arch_has_safe_halt()		0
+#define dyn_tick_reprogram_timer()	do {} while (0)
+#define dyn_tick_enabled()		0
+
+#endif	/* CONFIG_NO_IDLE_HZ */
+
+
+/* Pick up arch specific header */
+#include <asm/dyn-tick.h>
+
+#endif	/* _DYN_TICK_TIMER_H */
Index: linux-dev/kernel/Makefile
===================================================================
--- linux-dev.orig/kernel/Makefile	2005-06-10 10:34:42.000000000 -0700
+++ linux-dev/kernel/Makefile	2005-06-10 10:36:12.000000000 -0700
@@ -28,6 +28,7 @@
 obj-$(CONFIG_SYSFS) += ksysfs.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_SECCOMP) += seccomp.o
+obj-$(CONFIG_NO_IDLE_HZ) += dyn-tick.o
 
 ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
Index: linux-dev/kernel/dyn-tick.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-dev/kernel/dyn-tick.c	2005-06-10 11:35:31.000000000 -0700
@@ -0,0 +1,212 @@
+/*
+ * linux/arch/i386/kernel/dyn-tick.c
+ *
+ * Beginnings of generic dynamic tick timer support
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Tony Lindgen <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.
+ */
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sysdev.h>
+#include <linux/interrupt.h>
+#include <linux/cpumask.h>
+#include <linux/pm.h>
+#include <linux/dyn-tick.h>
+#include <asm/io.h>
+
+#include "io_ports.h"
+
+#define DYN_TICK_VERSION	"050610-1"
+
+struct dyn_tick_state dyn_tick_state;
+struct dyn_tick_state * dyn_tick = &dyn_tick_state;
+struct dyn_tick_timer * dyn_tick_cfg;
+static cpumask_t dyn_cpu_map;
+
+/*
+ * Arch independed code needed to reprogram next timer interrupt.
+ * Gets called from cpu_idle() before entering idle loop. Note that
+ * we want to have all processors idle before reprogramming the
+ * next timer interrupt.
+ */
+unsigned long dyn_tick_reprogram_timer(void)
+{
+	int cpu;
+	unsigned long flags;
+	cpumask_t idle_cpus;
+	unsigned long next;
+
+	if (!(dyn_tick->state & DYN_TICK_ENABLED))
+		return 0;
+
+	/* Check if we are already skipping ticks and can idle other cpus */
+	if (dyn_tick->state & DYN_TICK_SKIPPING) {
+		if (cpu_has_local_apic())
+			reprogram_apic_timer(dyn_tick->skip);
+		return 0;
+	}
+
+	/* Check if we can start skipping ticks */
+	write_seqlock_irqsave(&xtime_lock, flags);
+	cpu = smp_processor_id();
+	cpu_set(cpu, dyn_cpu_map);
+	cpus_and(idle_cpus, dyn_cpu_map, cpu_online_map);
+	if (cpus_equal(idle_cpus, cpu_online_map)) {
+		next = next_timer_interrupt();
+		if (jiffies > next)
+			dyn_tick->skip = 1;
+		else
+			dyn_tick->skip = next_timer_interrupt() - jiffies;
+		if (dyn_tick->skip > DYN_TICK_MIN_SKIP) {
+			if (dyn_tick->skip > dyn_tick->max_skip)
+				dyn_tick->skip = dyn_tick->max_skip;
+
+			dyn_tick_cfg->arch_reprogram_timer();
+
+			dyn_tick->skip_cpu = cpu;
+			dyn_tick->state |= DYN_TICK_SKIPPING;
+		}
+		cpus_clear(dyn_cpu_map);
+	}
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	return dyn_tick->skip;
+}
+
+void __init dyn_tick_register(struct dyn_tick_timer * arch_timer)
+{
+	dyn_tick_cfg = arch_timer;
+	printk(KERN_INFO "dyn-tick: Registering dynamic tick timer v%s\n",
+	       DYN_TICK_VERSION);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * Command line options
+ * ---------------------------------------------------------------------------
+ */
+static int __initdata dyntick_autoenable = 0;
+static int __initdata dyntick_useapic = 0;
+
+/*
+ * dyntick=[enable|disable],[forceapic]
+ */ 
+static int __init dyntick_setup(char *options)
+{
+	if (!options)
+		return 0;
+
+	if (!strncmp(options, "enable", 6)) 
+		dyntick_autoenable = 1;
+
+	if (strstr(options, "forceapic"))
+		dyntick_useapic = 1;
+
+	return 0;
+}
+
+__setup("dyntick=", dyntick_setup);
+
+/*
+ * ---------------------------------------------------------------------------
+ * Sysfs interface
+ * ---------------------------------------------------------------------------
+ */
+
+extern struct sys_device device_timer;
+
+#define DYN_TICK_IS_SET(x)	((dyn_tick->state & (x)) == (x))
+
+static ssize_t show_dyn_tick_state(struct sys_device *dev, char *buf)
+{
+	return sprintf(buf,
+		       "suitable:\t%i\n"
+		       "enabled:\t%i\n"
+		       "using APIC:\t%i\n",
+		       DYN_TICK_IS_SET(DYN_TICK_SUITABLE),
+		       DYN_TICK_IS_SET(DYN_TICK_ENABLED),
+		       DYN_TICK_IS_SET(DYN_TICK_USE_APIC));
+}
+
+static ssize_t set_dyn_tick_state(struct sys_device *dev, const char * buf,
+				size_t count)
+{
+	unsigned long flags;
+	unsigned int enable = simple_strtoul(buf, NULL, 2);
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+	if (enable) {
+		if (dyn_tick_cfg->arch_enable)
+			dyn_tick_cfg->arch_enable();
+		dyn_tick->state |= DYN_TICK_ENABLED;
+	} else {
+		if (dyn_tick_cfg->arch_disable)
+			dyn_tick_cfg->arch_disable();
+		dyn_tick->state &= ~DYN_TICK_ENABLED;
+	}
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	return count;
+}
+
+static SYSDEV_ATTR(dyn_tick_state, 0644, show_dyn_tick_state,
+		   set_dyn_tick_state);
+
+/*
+ * ---------------------------------------------------------------------------
+ * Init functions
+ * ---------------------------------------------------------------------------
+ */
+
+static int __init dyn_tick_early_init(void)
+{
+	dyn_tick->state |= DYN_TICK_TIMER_INT;
+	return 0;
+}
+
+subsys_initcall(dyn_tick_early_init);
+
+/*
+ * We need to initialize dynamic tick after calibrate delay
+ */
+static int __init dyn_tick_late_init(void)
+{
+	int ret = 0;
+
+	if (dyn_tick_cfg == NULL || dyn_tick_cfg->arch_init == NULL ||
+	    !(dyn_tick->state & DYN_TICK_SUITABLE)) {
+		printk(KERN_ERR "dyn-tick: No suitable timer found\n");
+		return -ENODEV;
+	}
+
+	if (!dyntick_useapic)
+		dyn_tick->state &= ~DYN_TICK_USE_APIC;
+
+	ret = dyn_tick_cfg->arch_init();
+	if (ret != 0) {
+		printk(KERN_ERR "dyn-tick: Init failed\n");
+		return -ENODEV;
+	}
+
+	ret = sysdev_create_file(&device_timer, &attr_dyn_tick_state);
+
+	if (ret == 0 && dyntick_autoenable) {
+		dyn_tick->state |= DYN_TICK_ENABLED;
+		printk(KERN_INFO "dyn-tick: Timer using dynamic tick\n");
+	} else
+		printk(KERN_INFO "dyn-tick: Timer not enabled during boot\n");
+
+	return ret;
+}
+
+late_initcall(dyn_tick_late_init);
Index: linux-dev/arch/i386/kernel/timers/timer_pit.c
===================================================================
--- linux-dev.orig/arch/i386/kernel/timers/timer_pit.c	2005-06-10 10:34:42.000000000 -0700
+++ linux-dev/arch/i386/kernel/timers/timer_pit.c	2005-06-10 10:36:12.000000000 -0700
@@ -149,6 +149,43 @@
 	return count;
 }
 
+/*
+ * REVISIT: Looks like on P3 APIC timer keeps running if PIT mode
+ *	    is changed. On P4, changing PIT mode seems to kill
+ *	    APIC timer interrupts. Same thing with disabling PIT
+ *	    interrupt.
+ */
+void disable_pit_timer(void)
+{
+	extern spinlock_t i8253_lock;
+	unsigned long flags;
+	spin_lock_irqsave(&i8253_lock, flags);
+	outb_p(0x32, PIT_MODE);		/* binary, mode 1, LSB/MSB, ch 0 */
+	spin_unlock_irqrestore(&i8253_lock, flags);
+}
+
+/*
+ * Reprograms the next timer interrupt
+ * PIT timer reprogramming code taken from APM code.
+ * Note that PIT timer is a 16-bit timer, which allows max
+ * skip of only few seconds.
+ */
+void reprogram_pit_timer(int jiffies_to_skip)
+{
+	int skip;
+	extern spinlock_t i8253_lock;
+	unsigned long flags;
+
+	skip = jiffies_to_skip * LATCH;
+	if (skip > 0xffff)
+		skip = 0xffff;
+
+	spin_lock_irqsave(&i8253_lock, flags);
+	outb_p(0x34, PIT_MODE);		/* binary, mode 2, LSB/MSB, ch 0 */
+	outb_p(skip & 0xff, PIT_CH0);	/* LSB */
+	outb(skip >> 8, PIT_CH0);	/* MSB */
+	spin_unlock_irqrestore(&i8253_lock, flags);
+}
 
 /* tsc timer_opts struct */
 struct timer_opts timer_pit = {

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-2
  2005-06-10  9:15         ` Pavel Machek
  2005-06-10 15:17           ` Tony Lindgren
@ 2005-06-11 17:59           ` Kyle Moffett
  1 sibling, 0 replies; 32+ messages in thread
From: Kyle Moffett @ 2005-06-11 17:59 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Tony Lindgren, Christian Hesse, linux-kernel

On Jun 10, 2005, at 05:15:15, Pavel Machek wrote:
> Hi!
>>> do {} while (0)
>>>
>>> , else you are preparing trap for someone.
>>>
>>
>> Can you please explain what the difference between these two are?
>> Some compiler version specific thing?
>>
>
> It took me quite some remembering. Problem is that with your macros,
> someone can write
>
>     dyn_tick_reprogram_timer()
>     printk();
>
> [notice missing ; at first line], and still get it compile. If you
> replace {} with do {} while (0), he'll get compile error as he should.

Actually, the real reason is for something like this:

#define myfunc1() {}
#define myfunc2() {}

if (a && b) myfunc1();
else        myfunc2();

This would be translated as:

if (a && b) {};
else        {};

Which would generate a syntax error:
zeus:~ kyle$ gcc -c `y -e .c` -o tmp.o <<'EOF'
 > #define myfunc1() {}
 > #define myfunc2() {}
 > void x() {
 >     int a = 0, b = 1;
 >     if (a && b) myfunc1();
 >     else        myfunc2();
 > }
 > EOF
/tmp/y.c8F08d.c: In function ‘x’:
/tmp/y.c8F08d.c:4: error: parse error before "else"

Cheers,
Kyle Moffett




^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050610-1
  2005-06-10 22:15             ` [PATCH] Dynamic tick for x86 version 050610-1 Tony Lindgren
@ 2005-06-18  3:34               ` hugang
  2005-06-18  6:30                 ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 32+ messages in thread
From: hugang @ 2005-06-18  3:34 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: linux-kernel, Pallipadi, Venkatesh, Jonathan Corbet,
	Pavel Machek, Bernard Blackham, Christian Hesse, Zwane Mwaikambo,
	benh

On Fri, Jun 10, 2005 at 03:15:01PM -0700, Tony Lindgren wrote:
> Hi all,
> 
> Here's yet another version with more clean-up:
> 
> - Got rid of ifdefs for skipping timer calibration; Skipping is
>   now done based on dyn_tick_enaled() instead.
> 
> - Clean-up fixes as suggested by Pavel Machek.
> 
> Cheers,
> 
> Tony

I'm try to port it powerpc, Here is a patch.

 Port Dynamic Tick Timer to new platform is easy. :)
  1) Find the reprogram timer interface.
  2) do a hook in the idle function.

That worked on my PowerBookG4 12'.

 arch/ppc/Kconfig           |   15 ++++++++
 arch/ppc/kernel/Makefile   |    1 
 arch/ppc/kernel/dyn-tick.c |   43 ++++++++++++++++++++++++
 arch/ppc/kernel/idle.c     |    4 +-
 arch/ppc/kernel/time.c     |   80 ++++++++++++++++++++++++++++++++++++++++++---
 include/asm-ppc/dyn-tick.h |   22 ++++++++++++
 kernel/Makefile            |    1 
 kernel/dyn-tick.c          |   39 ++++++++++++++++-----
 8 files changed, 190 insertions(+), 15 deletions(-)

Index: 2.6.11.9/arch/ppc/Kconfig
===================================================================
--- 2.6.11.9.orig/arch/ppc/Kconfig
+++ 2.6.11.9/arch/ppc/Kconfig
@@ -230,6 +230,21 @@ config PPC601_SYNC_FIX
 source arch/ppc/platforms/4xx/Kconfig
 source arch/ppc/platforms/85xx/Kconfig
 
+config NO_IDLE_HZ
+	bool "Dynamic Tick Timer - Skip timer ticks during idle"
+	help
+	  This option enables support for skipping timer ticks when the
+	  processor is idle. During system load, timer is continuous.
+	  This option saves power, as it allows the system to stay in
+	  idle mode longer. Currently supported timers are ACPI PM
+	  timer, local APIC timer, and TSC timer. HPET timer is currently
+	  not supported.
+
+	  Note that you need to enable dynamic tick timer either by
+	  passing dyntick=enable command line option, or via sysfs:
+
+	  # echo 1 > /sys/devices/system/timer/timer0/dyn_tick_state
+
 config PPC64BRIDGE
 	bool
 	depends on POWER3 || POWER4
Index: 2.6.11.9/arch/ppc/kernel/Makefile
===================================================================
--- 2.6.11.9.orig/arch/ppc/kernel/Makefile
+++ 2.6.11.9/arch/ppc/kernel/Makefile
@@ -30,3 +30,4 @@ ifndef CONFIG_MATH_EMULATION
 obj-$(CONFIG_8xx)		+= softemu8xx.o
 endif
 
+obj-$(CONFIG_NO_IDLE_HZ)    += dyn-tick.o
Index: 2.6.11.9/arch/ppc/kernel/dyn-tick.c
===================================================================
--- /dev/null
+++ 2.6.11.9/arch/ppc/kernel/dyn-tick.c
@@ -0,0 +1,43 @@
+/*
+ * linux/arch/ppc/kernel/dyn-tick.c
+ *
+ * Copyright (C) 2005 Beijing Soul
+ * Written by Hu Gang <hugang@soulinfo.com> and 
+ * Tony Lindgen <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.
+ */
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/dyn-tick.h>
+
+void arch_reprogram_timer(void)
+{
+	if (dyn_tick->state & DYN_TICK_TIMER_INT)
+		reprogram_tb_timer(dyn_tick->skip);
+	else
+		disable_tb_timer();
+}
+
+static struct dyn_tick_timer arch_dyn_tick_timer = {
+	.arch_reprogram_timer   = &arch_reprogram_timer,
+};
+
+int __init dyn_tick_init(void)
+{
+	arch_dyn_tick_timer.arch_init = dyn_tick_arch_init;
+	dyn_tick_register(&arch_dyn_tick_timer);
+
+//	dyn_tick->state |= DYN_TICK_DEBUG;
+	dyn_tick->state |= DYN_TICK_SUITABLE;
+
+	return 0;
+}
+arch_initcall(dyn_tick_init);
Index: 2.6.11.9/arch/ppc/kernel/idle.c
===================================================================
--- 2.6.11.9.orig/arch/ppc/kernel/idle.c
+++ 2.6.11.9/arch/ppc/kernel/idle.c
@@ -22,6 +22,7 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/sysctl.h>
+#include <linux/dyn-tick.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -39,6 +40,7 @@ void default_idle(void)
 	powersave = ppc_md.power_save;
 
 	if (!need_resched()) {
+		dyn_tick_reprogram_timer();
 		if (powersave != NULL)
 			powersave();
 #ifdef CONFIG_SMP
@@ -59,7 +61,7 @@ void default_idle(void)
  */
 void cpu_idle(void)
 {
-	for (;;)
+	for (;;) 
 		if (ppc_md.idle != NULL)
 			ppc_md.idle();
 		else
Index: 2.6.11.9/arch/ppc/kernel/time.c
===================================================================
--- 2.6.11.9.orig/arch/ppc/kernel/time.c
+++ 2.6.11.9/arch/ppc/kernel/time.c
@@ -57,6 +57,7 @@
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/profile.h>
+#include <linux/dyn-tick.h>
 
 #include <asm/segment.h>
 #include <asm/io.h>
@@ -126,15 +127,11 @@ EXPORT_SYMBOL(profile_pc);
  * with interrupts disabled.
  * We set it up to overflow again in 1/HZ seconds.
  */
-void timer_interrupt(struct pt_regs * regs)
+static void do_timer_interrupt(struct pt_regs * regs)
 {
 	int next_dec;
 	unsigned long cpu = smp_processor_id();
 	unsigned jiffy_stamp = last_jiffy_stamp(cpu);
-	extern void do_IRQ(struct pt_regs *);
-
-	if (atomic_read(&ppc_n_lost_interrupts) != 0)
-		do_IRQ(regs);
 
 	irq_enter();
 
@@ -190,6 +187,23 @@ void timer_interrupt(struct pt_regs * re
 	irq_exit();
 }
 
+static void (*timer_interrupt_func)(struct pt_regs * regs) = NULL;
+
+void timer_interrupt(struct pt_regs * regs)
+{
+	extern void do_IRQ(struct pt_regs *);
+
+	if (atomic_read(&ppc_n_lost_interrupts) != 0)
+		do_IRQ(regs);
+	
+	if (timer_interrupt_func) {
+		timer_interrupt_func(regs);
+		return;
+	}
+	
+	do_timer_interrupt(regs);
+}
+
 /*
  * This version of gettimeofday has microsecond resolution.
  */
@@ -281,7 +295,63 @@ int do_settimeofday(struct timespec *tv)
 }
 
 EXPORT_SYMBOL(do_settimeofday);
+#ifdef CONFIG_NO_IDLE_HZ
+void reprogram_tb_timer(int jiffies_to_skip)
+{
+	set_dec(tb_ticks_per_jiffy * jiffies_to_skip/* + get_dec()*/);
+}
+void disable_tb_timer(void)
+{
+	printk("FIXME: disable_tb_timer\n");
+}
+
+static inline void tb_get_tick(unsigned long long *val)
+{
+	*val = (get_tbl() | ((unsigned long long)get_tbu()<<32));
+}
+
+static unsigned long long last_tick;
+
+static void dyn_tick_timer_interrupt(struct pt_regs *regs)
+{
+	unsigned long long now;
+	int skipped = 0;
+
+	tb_get_tick(&now);
 
+	while (now - last_tick >= NS_TICK_LEN) {
+		last_tick += NS_TICK_LEN;
+		skipped ++;
+	}
+	if (skipped && (dyn_tick->state & DYN_TICK_DEBUG)) {
+		printk("p %d\n", skipped);
+	}
+
+	do_timer_interrupt(regs);
+
+	if (dyn_tick->state & (DYN_TICK_ENABLED | DYN_TICK_SKIPPING)) {
+		dyn_tick->state |= DYN_TICK_ENABLED;
+		dyn_tick->state &= ~DYN_TICK_SKIPPING;
+	}
+}
+
+int __init dyn_tick_arch_init(void)
+{
+	unsigned long flags;
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+	tb_get_tick(&last_tick);
+	dyn_tick->skip = 1;
+	dyn_tick->max_skip = 0xffff;
+	printk(KERN_INFO "dyn-tick: Maximum ticks to skip limited to %i, %llx\n",
+			dyn_tick->max_skip, last_tick);
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	timer_interrupt_func = dyn_tick_timer_interrupt;
+	
+	return 0;
+}
+#endif
 /* This function is only called on the boot processor */
 void __init time_init(void)
 {
Index: 2.6.11.9/include/asm-ppc/dyn-tick.h
===================================================================
--- /dev/null
+++ 2.6.11.9/include/asm-ppc/dyn-tick.h
@@ -0,0 +1,22 @@
+/*
+ * linux/include/asm-ppc/dyn-tick.h
+ *
+ * Copyright (C) 2005 Beijing Soul 
+ * Written by Hu Gang <hugang@soulinfo.com> and 
+ * Tony Lindgen <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.
+ *
+ */
+#ifndef _ASM_PPC_DYN_TICK_H_
+#define _ASM_PPC_DYN_TICK_H_
+
+#define cpu_has_local_apic()	0
+#define reprogram_apic_timer(x)	do {} while (0)
+
+extern int dyn_tick_arch_init(void);
+
+#endif
Index: 2.6.11.9/kernel/Makefile
===================================================================
--- 2.6.11.9.orig/kernel/Makefile
+++ 2.6.11.9/kernel/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
 obj-$(CONFIG_KPROBES) += kprobes.o
 obj-$(CONFIG_SYSFS) += ksysfs.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
+obj-$(CONFIG_NO_IDLE_HZ) += dyn-tick.o
 
 ifneq ($(CONFIG_IA64),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
Index: 2.6.11.9/kernel/dyn-tick.c
===================================================================
--- 2.6.11.9.orig/kernel/dyn-tick.c
+++ 2.6.11.9/kernel/dyn-tick.c
@@ -24,7 +24,9 @@
 #include <linux/dyn-tick.h>
 #include <asm/io.h>
 
+#ifdef CONFIG_X86
 #include "io_ports.h"
+#endif
 
 #define DYN_TICK_VERSION	"050610-1"
 
@@ -47,9 +49,9 @@ unsigned long dyn_tick_reprogram_timer(v
 	unsigned long next;
 
 	if (dyn_tick->state & DYN_TICK_DEBUG)
-		printk("i");
-	
-	if (!(dyn_tick->state & DYN_TICK_ENABLED))
+		printk("i, %d\n", dyn_tick->skip);
+
+	if (!(dyn_tick->state & DYN_TICK_ENABLED)) 
 		return 0;
 
 	/* Check if we are already skipping ticks and can idle other cpus */
@@ -67,8 +69,9 @@ unsigned long dyn_tick_reprogram_timer(v
 	if (cpus_equal(idle_cpus, cpu_online_map)) {
 		next = next_timer_interrupt();
 		if (jiffies > next) {
-			//printk("Too late? next: %lu jiffies: %lu\n",
-			//       next, jjiffies);
+			if (dyn_tick->state & DYN_TICK_DEBUG)
+				printk("Too late? next: %lu jiffies: %lu\n",
+					next, jiffies);
 			dyn_tick->skip = 1;
 		} else
 			dyn_tick->skip = next_timer_interrupt() - jiffies;
@@ -121,15 +124,31 @@ static int __init dyntick_setup(char *op
 }
 
 __setup("dyntick=", dyntick_setup);
-
+#ifndef CONFIG_X86
 /*
  * ---------------------------------------------------------------------------
  * Sysfs interface
  * ---------------------------------------------------------------------------
  */
-
+static struct sysdev_class timer_sysclass = {
+	set_kset_name("timer"),
+};
+
+struct sys_device device_timer = {
+	.id = 0,
+	.cls = &timer_sysclass,
+};
+
+static int time_init_device(void)
+{
+	int error = sysdev_class_register(&timer_sysclass);
+	if (!error)
+		error = sysdev_register(&device_timer);
+	return error;
+}
+#else
 extern struct sys_device device_timer;
-
+#endif
 #define DYN_TICK_IS_SET(x)	((dyn_tick->state & (x)) == (x))
 
 static ssize_t show_dyn_tick_state(struct sys_device *dev, char *buf)
@@ -239,7 +258,9 @@ static SYSDEV_ATTR(dyn_tick_dbg, 0644, s
 static int __init dyn_tick_late_init(void)
 {
 	int ret = 0;
-
+#ifndef CONFIG_X86
+	time_init_device();
+#endif
 	if (dyn_tick_cfg == NULL || dyn_tick_cfg->arch_init == NULL ||
 	    !(dyn_tick->state & DYN_TICK_SUITABLE)) {
 		printk(KERN_ERR "dyn-tick: No suitable timer found\n");

-- 
Hu Gang       .-.
              /v\
             // \\ 
Linux User  /(   )\  [204016]
GPG Key ID   ^^-^^   http://soulinfo.com/~hugang/hugang.asc

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050610-1
  2005-06-18  3:34               ` hugang
@ 2005-06-18  6:30                 ` Benjamin Herrenschmidt
  2005-06-21  1:28                   ` Tony Lindgren
  2005-07-19  6:51                   ` hugang
  0 siblings, 2 replies; 32+ messages in thread
From: Benjamin Herrenschmidt @ 2005-06-18  6:30 UTC (permalink / raw)
  To: hugang
  Cc: Tony Lindgren, linux-kernel, Pallipadi, Venkatesh,
	Jonathan Corbet, Pavel Machek, Bernard Blackham, Christian Hesse,
	Zwane Mwaikambo


> I'm try to port it powerpc, Here is a patch.
> 
>  Port Dynamic Tick Timer to new platform is easy. :)
>   1) Find the reprogram timer interface.
>   2) do a hook in the idle function.
> 
> That worked on my PowerBookG4 12'.

Did you get a measurable gain on power consumption ?

Last time I toyed with this, I didn't.

Ben.



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050610-1
  2005-06-18  6:30                 ` Benjamin Herrenschmidt
@ 2005-06-21  1:28                   ` Tony Lindgren
  2005-06-21  1:49                     ` Benjamin Herrenschmidt
  2005-07-19  6:51                   ` hugang
  1 sibling, 1 reply; 32+ messages in thread
From: Tony Lindgren @ 2005-06-21  1:28 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: hugang, Tony Lindgren, linux-kernel, Pallipadi, Venkatesh,
	Jonathan Corbet, Pavel Machek, Bernard Blackham, Christian Hesse,
	Zwane Mwaikambo

On Sat, Jun 18, 2005 at 04:30:32PM +1000, Benjamin Herrenschmidt wrote:
> 
> > I'm try to port it powerpc, Here is a patch.
> > 
> >  Port Dynamic Tick Timer to new platform is easy. :)
> >   1) Find the reprogram timer interface.
> >   2) do a hook in the idle function.
> > 
> > That worked on my PowerBookG4 12'.

Cool :)

> Did you get a measurable gain on power consumption ?
> 
> Last time I toyed with this, I didn't.

Just dyntick alone probably does not do much for power savings. The
trick is to figure out what all can be turned off for the longer idle
periods. And try to make the idle periods longer by cutting down on
polling.

Tony

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050610-1
  2005-06-21  1:28                   ` Tony Lindgren
@ 2005-06-21  1:49                     ` Benjamin Herrenschmidt
  2005-06-21  2:21                       ` Tony Lindgren
  0 siblings, 1 reply; 32+ messages in thread
From: Benjamin Herrenschmidt @ 2005-06-21  1:49 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: hugang, linux-kernel, Pallipadi, Venkatesh, Jonathan Corbet,
	Pavel Machek, Bernard Blackham, Christian Hesse, Zwane Mwaikambo

On Mon, 2005-06-20 at 18:28 -0700, Tony Lindgren wrote:
> On Sat, Jun 18, 2005 at 04:30:32PM +1000, Benjamin Herrenschmidt wrote:
> > 
> > > I'm try to port it powerpc, Here is a patch.
> > > 
> > >  Port Dynamic Tick Timer to new platform is easy. :)
> > >   1) Find the reprogram timer interface.
> > >   2) do a hook in the idle function.
> > > 
> > > That worked on my PowerBookG4 12'.
> 
> Cool :)
> 
> > Did you get a measurable gain on power consumption ?
> > 
> > Last time I toyed with this, I didn't.
> 
> Just dyntick alone probably does not do much for power savings. The
> trick is to figure out what all can be turned off for the longer idle
> periods. And try to make the idle periods longer by cutting down on
> polling.

I would have expected it to actually do increase savings due to avoiding
the cost of bringing the CPU back from deep NAP mode too often. It's
possible that my previous experiments were bogus in fact. It would be
very useful to have some statistics on how long we _actually_ sleep, I
supspect things like the network stack with all it's slow timer all
kicking at slightly different times for example are screwing us up a
little bit.

Ben.



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050610-1
  2005-06-21  1:49                     ` Benjamin Herrenschmidt
@ 2005-06-21  2:21                       ` Tony Lindgren
  0 siblings, 0 replies; 32+ messages in thread
From: Tony Lindgren @ 2005-06-21  2:21 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Tony Lindgren, hugang, linux-kernel, Pallipadi, Venkatesh,
	Jonathan Corbet, Pavel Machek, Bernard Blackham, Christian Hesse,
	Zwane Mwaikambo

On Tue, Jun 21, 2005 at 11:49:20AM +1000, Benjamin Herrenschmidt wrote:
> On Mon, 2005-06-20 at 18:28 -0700, Tony Lindgren wrote:
> > On Sat, Jun 18, 2005 at 04:30:32PM +1000, Benjamin Herrenschmidt wrote:
> > > 
> > > > I'm try to port it powerpc, Here is a patch.
> > > > 
> > > >  Port Dynamic Tick Timer to new platform is easy. :)
> > > >   1) Find the reprogram timer interface.
> > > >   2) do a hook in the idle function.
> > > > 
> > > > That worked on my PowerBookG4 12'.
> > 
> > Cool :)
> > 
> > > Did you get a measurable gain on power consumption ?
> > > 
> > > Last time I toyed with this, I didn't.
> > 
> > Just dyntick alone probably does not do much for power savings. The
> > trick is to figure out what all can be turned off for the longer idle
> > periods. And try to make the idle periods longer by cutting down on
> > polling.
> 
> I would have expected it to actually do increase savings due to avoiding
> the cost of bringing the CPU back from deep NAP mode too often. It's
> possible that my previous experiments were bogus in fact. It would be
> very useful to have some statistics on how long we _actually_ sleep, I
> supspect things like the network stack with all it's slow timer all
> kicking at slightly different times for example are screwing us up a
> little bit.

Yeah, and I've also noticed that my laptop does not stay in C2 mode, but
actually just spins around... Halt works though. Then the x86 keyboard
driver does polling if no keyboard is attached. And I believe netfilter
caused some polling too (unverified).  And then of course any kind of
CPU meter apps keep polling...

One way to test the idle savings is to temporarily disable the timer
interrupt so the system stays in idle while measuring. That does not
help with the other devices though.

I've been thinking about implementing something that would show up the
worst pollers. Maybe then have a program called polltop? :)

Tony

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050610-1
  2005-06-18  6:30                 ` Benjamin Herrenschmidt
  2005-06-21  1:28                   ` Tony Lindgren
@ 2005-07-19  6:51                   ` hugang
  2005-07-19 13:51                     ` Benjamin Herrenschmidt
  1 sibling, 1 reply; 32+ messages in thread
From: hugang @ 2005-07-19  6:51 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: hugang, Tony Lindgren, linux-kernel, Pallipadi, Venkatesh,
	Jonathan Corbet, Pavel Machek, Bernard Blackham, Christian Hesse,
	Zwane Mwaikambo

On Sat, Jun 18, 2005 at 04:30:32PM +1000, Benjamin Herrenschmidt wrote:
> 
> > I'm try to port it powerpc, Here is a patch.
> > 
> >  Port Dynamic Tick Timer to new platform is easy. :)
> >   1) Find the reprogram timer interface.
> >   2) do a hook in the idle function.
> > 
> > That worked on my PowerBookG4 12'.
> 
> Did you get a measurable gain on power consumption ?
> 
> Last time I toyed with this, I didn't.

Today I do a measurable about it. 

First I using 2.6.12 without dynamic enable and unplug the AC power,
I check the /proc/pmu/battery_0, like this.
--
 flags      : 00000011
 charge     : 907
 max_charge : 2863
 current    : -987
 voltage    : 10950
 time rem.  : 3600
--
I only intresting with current, that show the system power load. 

When I enable dynamic, The current can low at -900.

So, It works. :>

2.6.12 + suspend2 + ck3 + dynamic 
http://soulinfo.com/~hugang/kernel/linux-2.6.12/

-- 
Hu Gang       .-.    Steve
              /v\
             // \\ 
            /(   )\
GPG Key ID   ^^-^^   http://soulinfo.com/~hugang/hugang.asc

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050610-1
  2005-07-19  6:51                   ` hugang
@ 2005-07-19 13:51                     ` Benjamin Herrenschmidt
  2005-07-25 10:11                       ` Tony Lindgren
  0 siblings, 1 reply; 32+ messages in thread
From: Benjamin Herrenschmidt @ 2005-07-19 13:51 UTC (permalink / raw)
  To: hugang
  Cc: Tony Lindgren, linux-kernel, Pallipadi, Venkatesh,
	Jonathan Corbet, Pavel Machek, Bernard Blackham, Christian Hesse,
	Zwane Mwaikambo

On Tue, 2005-07-19 at 14:51 +0800, hugang@soulinfo.com wrote:
> On Sat, Jun 18, 2005 at 04:30:32PM +1000, Benjamin Herrenschmidt wrote:
> > 
> > > I'm try to port it powerpc, Here is a patch.
> > > 
> > >  Port Dynamic Tick Timer to new platform is easy. :)
> > >   1) Find the reprogram timer interface.
> > >   2) do a hook in the idle function.
> > > 
> > > That worked on my PowerBookG4 12'.
> > 
> > Did you get a measurable gain on power consumption ?
> > 
> > Last time I toyed with this, I didn't.
> 
> Today I do a measurable about it. 
> 
> First I using 2.6.12 without dynamic enable and unplug the AC power,
> I check the /proc/pmu/battery_0, like this.
> --
>  flags      : 00000011
>  charge     : 907
>  max_charge : 2863
>  current    : -987
>  voltage    : 10950
>  time rem.  : 3600
> --
> I only intresting with current, that show the system power load. 
> 
> When I enable dynamic, The current can low at -900.

The numbers are repeatable ? I mean, if you actually let it settle down
in both cases ? Also, you should be careful about "parasites" in the
measurement, like pbbuttons dimming the backlight, the hard disk going
to sleep etc...

>From your numbers you get something like 10% improvement, which isn't
too bad.

Ben.



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050610-1
  2005-07-19 13:51                     ` Benjamin Herrenschmidt
@ 2005-07-25 10:11                       ` Tony Lindgren
  0 siblings, 0 replies; 32+ messages in thread
From: Tony Lindgren @ 2005-07-25 10:11 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: hugang, linux-kernel, Pallipadi, Venkatesh, Jonathan Corbet,
	Pavel Machek, Bernard Blackham, Christian Hesse, Zwane Mwaikambo

* Benjamin Herrenschmidt <benh@kernel.crashing.org> [050719 06:55]:
> On Tue, 2005-07-19 at 14:51 +0800, hugang@soulinfo.com wrote:
> > On Sat, Jun 18, 2005 at 04:30:32PM +1000, Benjamin Herrenschmidt wrote:
> > > 
> > > > I'm try to port it powerpc, Here is a patch.
> > > > 
> > > >  Port Dynamic Tick Timer to new platform is easy. :)
> > > >   1) Find the reprogram timer interface.
> > > >   2) do a hook in the idle function.
> > > > 
> > > > That worked on my PowerBookG4 12'.
> > > 
> > > Did you get a measurable gain on power consumption ?
> > > 
> > > Last time I toyed with this, I didn't.
> > 
> > Today I do a measurable about it. 
> > 
> > First I using 2.6.12 without dynamic enable and unplug the AC power,
> > I check the /proc/pmu/battery_0, like this.
> > --
> >  flags      : 00000011
> >  charge     : 907
> >  max_charge : 2863
> >  current    : -987
> >  voltage    : 10950
> >  time rem.  : 3600
> > --
> > I only intresting with current, that show the system power load. 
> > 
> > When I enable dynamic, The current can low at -900.
> 
> The numbers are repeatable ? I mean, if you actually let it settle down
> in both cases ? Also, you should be careful about "parasites" in the
> measurement, like pbbuttons dimming the backlight, the hard disk going
> to sleep etc...
> 
> >From your numbers you get something like 10% improvement, which isn't
> too bad.

Just quick update here, I'm back from vacation and will try to
post updated dyn-tick patch soon with the PPC patch integrated.

Tony

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH] Dynamic tick for x86 version 050602-1
  2005-06-08 22:14 Pallipadi, Venkatesh
@ 2005-06-09  1:40 ` Tony Lindgren
  0 siblings, 0 replies; 32+ messages in thread
From: Tony Lindgren @ 2005-06-09  1:40 UTC (permalink / raw)
  To: Pallipadi, Venkatesh; +Cc: Jonathan Corbet, linux-kernel

* Pallipadi, Venkatesh <venkatesh.pallipadi@intel.com> [050608 15:14]:
> 
> >-----Original Message-----
> >From: linux-kernel-owner@vger.kernel.org 
> >[mailto:linux-kernel-owner@vger.kernel.org] On Behalf Of 
> >Jonathan Corbet
> >Sent: Tuesday, June 07, 2005 1:36 PM
> >To: Tony Lindgren
> >Cc: linux-kernel@vger.kernel.org
> >Subject: Re: [PATCH] Dynamic tick for x86 version 050602-1 
> >
> >Tony Lindgren <tony@atomide.com> wrote:
> >
> >> --- linux-dev.orig/arch/i386/kernel/irq.c	2005-06-01 
> >17:51:36.000000000 -0700
> >> +++ linux-dev/arch/i386/kernel/irq.c	2005-06-01 
> >17:54:32.000000000 -0700
> >> [...]
> >> @@ -102,6 +103,12 @@ fastcall unsigned int do_IRQ(struct pt_r
> >>  		);
> >>  	} else
> >>  #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
> >> +
> >>  		__do_IRQ(irq, regs);
> >
> >Forgive me if I'm being obtuse (again...), but this hunk doesn't look
> >like it would work well in the 4K stacks case.  When 4K stacks 
> >are being
> >used, dyn_tick->interrupt() will only get called in the nested 
> >interrupt
> >case, when the interrupt stack is already in use.  This change also
> >pushes the non-assembly __do_IRQ() call out of the else branch, meaning
> >that, when the switch is made to the interrupt stack (most of 
> >the time),
> >__do_IRQ() will be called twice for the same interrupt.
> >
> >It looks to me like you want to put your #ifdef chunk *after* the call
> >to __do_IRQ(), unless you have some reason for needing it to happen
> >before the regular interrupt handler is invoked.
> >
> 
> Good catch. This indeed looks like a bug. 
> With 050602-1 version I am seeing double the number of calls to 
> timer_interrupt routine than expected. Say, when all CPUs are fully
> busy, 
> I see 2*HZ timer interrupt count in /proc/interrupts
> 
> And things look normal once I change this hunk as below
> 
> >>  	} else
> >>  #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
> >> +
> >>  		__do_IRQ(irq, regs);
>    + }

Cool. Sorry for not responding earlier, my hard drive crashed yesterday
morning... I also managed to fry my spare computer's motherboard
while trying to recover some data from the broken disk :)

I'll try to post an updated patch tomorrow.

Tony

^ permalink raw reply	[flat|nested] 32+ messages in thread

* RE: [PATCH] Dynamic tick for x86 version 050602-1
@ 2005-06-08 22:14 Pallipadi, Venkatesh
  2005-06-09  1:40 ` Tony Lindgren
  0 siblings, 1 reply; 32+ messages in thread
From: Pallipadi, Venkatesh @ 2005-06-08 22:14 UTC (permalink / raw)
  To: Jonathan Corbet, Tony Lindgren; +Cc: linux-kernel


>-----Original Message-----
>From: linux-kernel-owner@vger.kernel.org 
>[mailto:linux-kernel-owner@vger.kernel.org] On Behalf Of 
>Jonathan Corbet
>Sent: Tuesday, June 07, 2005 1:36 PM
>To: Tony Lindgren
>Cc: linux-kernel@vger.kernel.org
>Subject: Re: [PATCH] Dynamic tick for x86 version 050602-1 
>
>Tony Lindgren <tony@atomide.com> wrote:
>
>> --- linux-dev.orig/arch/i386/kernel/irq.c	2005-06-01 
>17:51:36.000000000 -0700
>> +++ linux-dev/arch/i386/kernel/irq.c	2005-06-01 
>17:54:32.000000000 -0700
>> [...]
>> @@ -102,6 +103,12 @@ fastcall unsigned int do_IRQ(struct pt_r
>>  		);
>>  	} else
>>  #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
>> +
>>  		__do_IRQ(irq, regs);
>
>Forgive me if I'm being obtuse (again...), but this hunk doesn't look
>like it would work well in the 4K stacks case.  When 4K stacks 
>are being
>used, dyn_tick->interrupt() will only get called in the nested 
>interrupt
>case, when the interrupt stack is already in use.  This change also
>pushes the non-assembly __do_IRQ() call out of the else branch, meaning
>that, when the switch is made to the interrupt stack (most of 
>the time),
>__do_IRQ() will be called twice for the same interrupt.
>
>It looks to me like you want to put your #ifdef chunk *after* the call
>to __do_IRQ(), unless you have some reason for needing it to happen
>before the regular interrupt handler is invoked.
>

Good catch. This indeed looks like a bug. 
With 050602-1 version I am seeing double the number of calls to 
timer_interrupt routine than expected. Say, when all CPUs are fully
busy, 
I see 2*HZ timer interrupt count in /proc/interrupts

And things look normal once I change this hunk as below

>>  	} else
>>  #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
>> +
>>  		__do_IRQ(irq, regs);
   + }



Thanks,
Venki

^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2005-07-25 10:12 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-06-02  1:36 [PATCH] Dynamic tick for x86 version 050602-1 Tony Lindgren
2005-06-02  1:54 ` Zwane Mwaikambo
2005-06-02  2:09   ` Tony Lindgren
2005-06-02  8:30 ` Christian Hesse
2005-06-02 17:42   ` [PATCH] Dynamic tick for x86 version 050602-2 Tony Lindgren
2005-06-02 20:03     ` Christian Hesse
2005-06-02 20:32       ` Tony Lindgren
2005-06-03  6:08         ` Christian Hesse
2005-06-03 17:39           ` Tony Lindgren
2005-06-04 12:51             ` Christian Hesse
2005-06-10  4:03               ` Tony Lindgren
2005-06-05  4:06       ` Bernard Blackham
2005-06-10  4:05         ` Tony Lindgren
2005-06-03 22:37     ` Pavel Machek
2005-06-03 22:47       ` Pavel Machek
2005-06-10  4:17       ` Tony Lindgren
2005-06-10  9:15         ` Pavel Machek
2005-06-10 15:17           ` Tony Lindgren
2005-06-10 22:15             ` [PATCH] Dynamic tick for x86 version 050610-1 Tony Lindgren
2005-06-18  3:34               ` hugang
2005-06-18  6:30                 ` Benjamin Herrenschmidt
2005-06-21  1:28                   ` Tony Lindgren
2005-06-21  1:49                     ` Benjamin Herrenschmidt
2005-06-21  2:21                       ` Tony Lindgren
2005-07-19  6:51                   ` hugang
2005-07-19 13:51                     ` Benjamin Herrenschmidt
2005-07-25 10:11                       ` Tony Lindgren
2005-06-11 17:59           ` [PATCH] Dynamic tick for x86 version 050602-2 Kyle Moffett
2005-06-07 20:36 ` [PATCH] Dynamic tick for x86 version 050602-1 Jonathan Corbet
2005-06-10  4:18   ` Tony Lindgren
2005-06-08 22:14 Pallipadi, Venkatesh
2005-06-09  1:40 ` Tony Lindgren

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.