All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/5] x86_64: enable clockevents and dynticks
@ 2007-03-31  8:31 Chris Wright
  2007-03-31  8:31 ` [RFC PATCH 1/5] x86_64: untangle asm/hpet.h from asm/timex.h Chris Wright
                   ` (6 more replies)
  0 siblings, 7 replies; 17+ messages in thread
From: Chris Wright @ 2007-03-31  8:31 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, john stultz, Andi Kleen; +Cc: linux-kernel

This series converts x86_64 timers to clockevents drivers
and then enables dynticks.  There's some minor cleanups along
the way.  The lapic broadcast mechanism is untested, I'm sure it
still needs work, there's still some cruft in lapic_setup_timer.

This is just for comments at this point, now that it's working
on my test box in both NO_HZ=n and NO_HZ=n configurations (typically
using hpet).

thanks,
-chris
--

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

* [RFC PATCH 1/5] x86_64: untangle asm/hpet.h from asm/timex.h
  2007-03-31  8:31 [RFC PATCH 0/5] x86_64: enable clockevents and dynticks Chris Wright
@ 2007-03-31  8:31 ` Chris Wright
  2007-03-31  8:31 ` [RFC PATCH 2/5] x86_64: drive set_rtc_mss from standalone timer Chris Wright
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 17+ messages in thread
From: Chris Wright @ 2007-03-31  8:31 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, john stultz, Andi Kleen; +Cc: linux-kernel

[-- Attachment #1: x86_64-remove-hpet-from-timex.patch --]
[-- Type: text/plain, Size: 1765 bytes --]

When making changes to x86_64 timers, I noticed that touching
hpet.h triggered an unreasonably large rebuild.  Untangling
it from timex.h quiets the extra rebuild quite a bit.

Signed-off-by: Chris Wright <chrisw@sous-sol.org>
Cc: Andi Kleen <ak@suse.de>
---
 drivers/char/rtc.c         |    2 +-
 include/asm-x86_64/apic.h  |    1 +
 include/asm-x86_64/hpet.h  |    1 -
 include/asm-x86_64/timex.h |    1 -
 4 files changed, 2 insertions(+), 3 deletions(-)

--- linus-2.6.orig/drivers/char/rtc.c
+++ linus-2.6/drivers/char/rtc.c
@@ -82,7 +82,7 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-#if defined(__i386__)
+#if defined(__i386__) || defined(__x86_64__)
 #include <asm/hpet.h>
 #endif
 
--- linus-2.6.orig/include/asm-x86_64/timex.h
+++ linus-2.6/include/asm-x86_64/timex.h
@@ -9,7 +9,6 @@
 #include <asm/8253pit.h>
 #include <asm/msr.h>
 #include <asm/vsyscall.h>
-#include <asm/hpet.h>
 #include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/tsc.h>
--- linus-2.6.orig/include/asm-x86_64/apic.h
+++ linus-2.6/include/asm-x86_64/apic.h
@@ -84,6 +84,7 @@ extern int APIC_init_uniprocessor (void)
 extern void disable_APIC_timer(void);
 extern void enable_APIC_timer(void);
 extern void clustered_apic_check(void);
+extern int apic_is_clustered_box(void);
 
 extern void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
 				   unsigned char msg_type, unsigned char mask);
--- linus-2.6.orig/include/asm-x86_64/hpet.h
+++ linus-2.6/include/asm-x86_64/hpet.h
@@ -55,7 +55,6 @@
 
 extern int is_hpet_enabled(void);
 extern int hpet_rtc_timer_init(void);
-extern int apic_is_clustered_box(void);
 extern int hpet_arch_init(void);
 extern int hpet_timer_stop_set_go(unsigned long tick);
 extern int hpet_reenable(void);

--

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

* [RFC PATCH 2/5] x86_64: drive set_rtc_mss from standalone timer
  2007-03-31  8:31 [RFC PATCH 0/5] x86_64: enable clockevents and dynticks Chris Wright
  2007-03-31  8:31 ` [RFC PATCH 1/5] x86_64: untangle asm/hpet.h from asm/timex.h Chris Wright
@ 2007-03-31  8:31 ` Chris Wright
  2007-03-31  8:31 ` [RFC PATCH 3/5] x86_64: clockevents drivers Chris Wright
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 17+ messages in thread
From: Chris Wright @ 2007-03-31  8:31 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, john stultz, Andi Kleen; +Cc: linux-kernel

[-- Attachment #1: x86_64-use-timer-for-set_rtc_mmss.patch --]
[-- Type: text/plain, Size: 3481 bytes --]

This is how it's done on i386, and it makes one less bit
of code to trim from main_timer_handler() when converting
to clockevents.

Signed-off-by: Chris Wright <chrisw@sous-sol.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: john stultz <johnstul@us.ibm.com>
Cc: Andi Kleen <ak@suse.de>
---
 arch/x86_64/kernel/time.c |   68 +++++++++++++++++++++++++++++++++++-----------
 1 file changed, 52 insertions(+), 16 deletions(-)

--- linus-2.6.orig/arch/x86_64/kernel/time.c
+++ linus-2.6/arch/x86_64/kernel/time.c
@@ -81,8 +81,9 @@ EXPORT_SYMBOL(profile_pc);
  * sheet for details.
  */
 
-static void set_rtc_mmss(unsigned long nowtime)
+static int set_rtc_mmss(unsigned long nowtime)
 {
+	int retval = 0;
 	int real_seconds, real_minutes, cmos_minutes;
 	unsigned char control, freq_select;
 
@@ -122,6 +123,7 @@ static void set_rtc_mmss(unsigned long n
 	if (abs(real_minutes - cmos_minutes) >= 30) {
 		printk(KERN_WARNING "time.c: can't update CMOS clock "
 		       "from %d to %d\n", cmos_minutes, real_minutes);
+		retval = -1;
 	} else {
 		BIN_TO_BCD(real_seconds);
 		BIN_TO_BCD(real_minutes);
@@ -141,12 +143,60 @@ static void set_rtc_mmss(unsigned long n
 	CMOS_WRITE(freq_select, RTC_FREQ_SELECT);
 
 	spin_unlock(&rtc_lock);
+
+	return retval;
+}
+
+static void sync_cmos_clock(unsigned long dummy);
+
+static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);
+
+static void sync_cmos_clock(unsigned long dummy)
+{
+	struct timespec now, next;
+	int fail = 1;
+
+	/*
+	 * If we have an externally synchronized Linux clock, then update
+	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+	 * called as close as possible to 500 ms before the new second starts.
+	 * This code is run on a timer.  If the clock is set, that timer
+	 * may not expire at the correct time.  Thus, we adjust...
+	 */
+	if (!ntp_synced())
+		/*
+		 * Not synced, exit, do not restart a timer (if one is
+		 * running, let it run out).
+		 */
+		return;
+
+	getnstimeofday(&now);
+	if (abs(xtime.tv_nsec - 500000000) <= tick_nsec / 2)
+		fail = set_rtc_mmss(now.tv_sec);
+
+	next.tv_nsec = 500000000 - now.tv_nsec;
+	if (next.tv_nsec <= 0)
+		next.tv_nsec += NSEC_PER_SEC;
+
+	if (!fail)
+		next.tv_sec = 659;
+	else
+		next.tv_sec = 0;
+
+	if (next.tv_nsec >= NSEC_PER_SEC) {
+		next.tv_sec++;
+		next.tv_nsec -= NSEC_PER_SEC;
+	}
+	mod_timer(&sync_cmos_timer, jiffies + timespec_to_jiffies(&next));
 }
 
+void notify_arch_cmos_timer(void)
+{
+	mod_timer(&sync_cmos_timer, jiffies + 1);
+}
 
 void main_timer_handler(void)
 {
-	static unsigned long rtc_update = 0;
 /*
  * Here we are in the timer irq handler. We have irqs locally disabled (so we
  * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running
@@ -174,20 +224,6 @@ void main_timer_handler(void)
 	if (!using_apic_timer)
 		smp_local_timer_interrupt();
 
-/*
- * If we have an externally synchronized Linux clock, then update CMOS clock
- * accordingly every ~11 minutes. set_rtc_mmss() will be called in the jiffy
- * closest to exactly 500 ms before the next second. If the update fails, we
- * don't care, as it'll be updated on the next turn, and the problem (time way
- * off) isn't likely to go away much sooner anyway.
- */
-
-	if (ntp_synced() && xtime.tv_sec > rtc_update &&
-		abs(xtime.tv_nsec - 500000000) <= tick_nsec / 2) {
-		set_rtc_mmss(xtime.tv_sec);
-		rtc_update = xtime.tv_sec + 660;
-	}
- 
 	write_sequnlock(&xtime_lock);
 }
 

--

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

* [RFC PATCH 3/5] x86_64: clockevents drivers
  2007-03-31  8:31 [RFC PATCH 0/5] x86_64: enable clockevents and dynticks Chris Wright
  2007-03-31  8:31 ` [RFC PATCH 1/5] x86_64: untangle asm/hpet.h from asm/timex.h Chris Wright
  2007-03-31  8:31 ` [RFC PATCH 2/5] x86_64: drive set_rtc_mss from standalone timer Chris Wright
@ 2007-03-31  8:31 ` Chris Wright
  2007-03-31  8:31 ` [RFC PATCH 4/5] x86_64: prep idle loop for dynticks Chris Wright
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 17+ messages in thread
From: Chris Wright @ 2007-03-31  8:31 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, john stultz, Andi Kleen; +Cc: linux-kernel

[-- Attachment #1: x86_64-clockevents.patch --]
[-- Type: text/plain, Size: 21664 bytes --]

Convert lapic, pit and hpet based timers to clockevents.
This brings x86_64 in line with i386.  And it is needed
to enable dynticks.

Signed-off-by: Chris Wright <chrisw@sous-sol.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: john stultz <johnstul@us.ibm.com>
Cc: Andi Kleen <ak@suse.de>
---
 arch/x86_64/Kconfig       |    8 +
 arch/x86_64/kernel/apic.c |  123 ++++++++++++++++++++-------
 arch/x86_64/kernel/hpet.c |  168 +++++++++++++++++++++++++++++--------
 arch/x86_64/kernel/time.c |  204 ++++++++++++++++------------------------------
 include/asm-x86_64/hpet.h |    2 
 5 files changed, 307 insertions(+), 198 deletions(-)

--- linus-2.6.orig/arch/x86_64/kernel/time.c
+++ linus-2.6/arch/x86_64/kernel/time.c
@@ -42,10 +42,19 @@
 #include <linux/cpufreq.h>
 #include <linux/hpet.h>
 #include <asm/apic.h>
+#include <linux/clockchips.h>
+#include <asm/delay.h>
 #include <asm/hpet.h>
 
 extern void i8254_timer_resume(void);
 extern int using_apic_timer;
+extern struct clock_event_device pit_clockevent;
+/*
+ * HPET replaces the PIT, when enabled. So we need to know, which of
+ * the two timers is used
+ */
+struct clock_event_device *global_clock_event;
+
 
 static char *timename = NULL;
 
@@ -197,34 +206,7 @@ void notify_arch_cmos_timer(void)
 
 void main_timer_handler(void)
 {
-/*
- * Here we are in the timer irq handler. We have irqs locally disabled (so we
- * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running
- * on the other CPU, so we need a lock. We also need to lock the vsyscall
- * variables, because both do_timer() and us change them -arca+vojtech
- */
-
-	write_seqlock(&xtime_lock);
-
-/*
- * Do the timer stuff.
- */
-
-	do_timer(1);
-#ifndef CONFIG_SMP
-	update_process_times(user_mode(get_irq_regs()));
-#endif
-
-/*
- * In the SMP case we use the local APIC timer interrupt to do the profiling,
- * except when we simulate SMP mode on a uniprocessor system, in that case we
- * have to call the local interrupt handler.
- */
-
-	if (!using_apic_timer)
-		smp_local_timer_interrupt();
-
-	write_sequnlock(&xtime_lock);
+	global_clock_event->event_handler(global_clock_event);
 }
 
 static irqreturn_t timer_interrupt(int irq, void *dev_id)
@@ -237,7 +219,7 @@ static irqreturn_t timer_interrupt(int i
 	return IRQ_HANDLED;
 }
 
-static unsigned long get_cmos_time(void)
+unsigned long read_persistent_clock(void)
 {
 	unsigned int year, mon, day, hour, min, sec;
 	unsigned long flags;
@@ -321,38 +303,80 @@ static unsigned int __init pit_calibrate
 #define PIT_MODE 0x43
 #define PIT_CH0  0x40
 
-static void __init __pit_init(int val, u8 mode)
+static void init_pit_timer(enum clock_event_mode mode,
+			   struct clock_event_device *evt)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&i8253_lock, flags);
-	outb_p(mode, PIT_MODE);
-	outb_p(val & 0xff, PIT_CH0);	/* LSB */
-	outb_p(val >> 8, PIT_CH0);	/* MSB */
+
+	switch(mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		/* binary, mode 2, LSB/MSB, ch 0 */
+		outb_p(0x34, PIT_MODE);
+		udelay(10);
+		outb_p(LATCH & 0xff , PIT_CH0); /* LSB */
+		outb(LATCH >> 8 , PIT_CH0);     /* MSB */
+		break;
+
+	case CLOCK_EVT_MODE_ONESHOT:
+		/* One shot setup */
+		outb_p(0x38, PIT_MODE);
+		udelay(10);
+		break;
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	case CLOCK_EVT_MODE_UNUSED:
+		outb_p(0x30, PIT_MODE);
+		outb_p(0, PIT_CH0);	/* LSB */
+		outb_p(0, PIT_CH0);	/* MSB */
+		break;
+	}
 	spin_unlock_irqrestore(&i8253_lock, flags);
 }
 
-void __init pit_init(void)
+static int pit_next_event(unsigned long delta, struct clock_event_device *evt)
 {
-	__pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8253_lock, flags);
+	outb_p(delta & 0xff , PIT_CH0); /* LSB */
+	outb(delta >> 8 , PIT_CH0);     /* MSB */
+	spin_unlock_irqrestore(&i8253_lock, flags);
+
+	return 0;
 }
 
-void __init pit_stop_interrupt(void)
+struct clock_event_device pit_clockevent = {
+	.name		= "pit",
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.set_mode       = init_pit_timer,
+	.set_next_event = pit_next_event,
+	.shift		= 32,
+	.irq		= 0,
+};
+
+void __init stop_timer_interrupt(void)
 {
-	__pit_init(0, 0x30); /* mode 0 */
+	/* XXX this is bogus */
+	clockevents_set_mode(global_clock_event, CLOCK_EVT_MODE_SHUTDOWN);
+	printk(KERN_INFO "timer: %s interrupt stopped.\n", global_clock_event->name);
 }
 
-void __init stop_timer_interrupt(void)
+static void __init setup_pit_timer(void)
 {
-	char *name;
-	if (hpet_address) {
-		name = "HPET";
-		hpet_timer_stop_set_go(0);
-	} else {
-		name = "PIT";
-		pit_stop_interrupt();
-	}
-	printk(KERN_INFO "timer: %s interrupt stopped.\n", name);
+	/*
+	 * Start pit with the boot cpu mask and make it global after the
+	 * IO_APIC has been initialized.
+	 */
+	pit_clockevent.cpumask = cpumask_of_cpu(0);
+
+	pit_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, 32);
+	pit_clockevent.max_delta_ns =
+		clockevent_delta2ns(0x7FFF, &pit_clockevent);
+	pit_clockevent.min_delta_ns =
+		clockevent_delta2ns(0xF, &pit_clockevent);
+	clockevents_register_device(&pit_clockevent);
+	global_clock_event = &pit_clockevent;
 }
 
 static struct irqaction irq0 = {
@@ -361,16 +385,8 @@ static struct irqaction irq0 = {
 
 void __init time_init(void)
 {
-	if (nohpet)
-		hpet_address = 0;
-	xtime.tv_sec = get_cmos_time();
-	xtime.tv_nsec = 0;
-
-	set_normalized_timespec(&wall_to_monotonic,
-	                        -xtime.tv_sec, -xtime.tv_nsec);
-
-	if (hpet_arch_init())
-		hpet_address = 0;
+	if (!hpet_arch_init())
+		setup_pit_timer();
 
 	if (hpet_use_timer) {
 		/* set tick_nsec to use the proper rate for HPET */
@@ -378,7 +394,6 @@ void __init time_init(void)
 		cpu_khz = hpet_calibrate_tsc();
 		timename = "HPET";
 	} else {
-		pit_init();
 		cpu_khz = pit_calibrate_tsc();
 		timename = "PIT";
 	}
@@ -398,76 +413,3 @@ void __init time_init(void)
 
 	setup_irq(0, &irq0);
 }
-
-
-static long clock_cmos_diff;
-static unsigned long sleep_start;
-
-/*
- * sysfs support for the timer.
- */
-
-static int timer_suspend(struct sys_device *dev, pm_message_t state)
-{
-	/*
-	 * Estimate time zone so that set_time can update the clock
-	 */
-	long cmos_time =  get_cmos_time();
-
-	clock_cmos_diff = -cmos_time;
-	clock_cmos_diff += get_seconds();
-	sleep_start = cmos_time;
-	return 0;
-}
-
-static int timer_resume(struct sys_device *dev)
-{
-	unsigned long flags;
-	unsigned long sec;
-	unsigned long ctime = get_cmos_time();
-	long sleep_length = (ctime - sleep_start) * HZ;
-
-	if (sleep_length < 0) {
-		printk(KERN_WARNING "Time skew detected in timer resume!\n");
-		/* The time after the resume must not be earlier than the time
-		 * before the suspend or some nasty things will happen
-		 */
-		sleep_length = 0;
-		ctime = sleep_start;
-	}
-	if (hpet_address)
-		hpet_reenable();
-	else
-		i8254_timer_resume();
-
-	sec = ctime + clock_cmos_diff;
-	write_seqlock_irqsave(&xtime_lock,flags);
-	xtime.tv_sec = sec;
-	xtime.tv_nsec = 0;
-	jiffies += sleep_length;
-	write_sequnlock_irqrestore(&xtime_lock,flags);
-	touch_softlockup_watchdog();
-	return 0;
-}
-
-static struct sysdev_class timer_sysclass = {
-	.resume = timer_resume,
-	.suspend = timer_suspend,
-	set_kset_name("timer"),
-};
-
-/* XXX this sysfs stuff should probably go elsewhere later -john */
-static 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;
-}
-
-device_initcall(time_init_device);
--- linus-2.6.orig/arch/x86_64/kernel/hpet.c
+++ linus-2.6/arch/x86_64/kernel/hpet.c
@@ -4,6 +4,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/time.h>
 #include <linux/clocksource.h>
+#include <linux/clockchips.h>
 #include <linux/ioport.h>
 #include <linux/acpi.h>
 #include <linux/hpet.h>
@@ -11,6 +12,7 @@
 #include <asm/vsyscall.h>
 #include <asm/timex.h>
 #include <asm/hpet.h>
+#include <asm/delay.h>
 
 #define HPET_MASK	0xFFFFFFFF
 #define HPET_SHIFT	22
@@ -27,6 +29,13 @@ unsigned long hpet_tick;	/* HPET clocks 
 int hpet_use_timer;		/* Use counter of hpet for time keeping,
 				 * otherwise PIT
 				 */
+static int hpet_legacy_int_enabled;
+extern struct clock_event_device *global_clock_event;
+
+static inline int is_hpet_capable(void)
+{
+	return (!nohpet && hpet_address);
+}
 
 #ifdef	CONFIG_HPET
 static __init int late_hpet_init(void)
@@ -34,7 +43,7 @@ static __init int late_hpet_init(void)
 	struct hpet_data	hd;
 	unsigned int 		ntimer;
 
-	if (!hpet_address)
+	if (!is_hpet_capable())
         	return 0;
 
 	memset(&hd, 0, sizeof(hd));
@@ -77,44 +86,107 @@ static __init int late_hpet_init(void)
 fs_initcall(late_hpet_init);
 #endif
 
-int hpet_timer_stop_set_go(unsigned long tick)
-{
-	unsigned int cfg;
+/*
+ * Common hpet info
+ */
+static void hpet_set_mode(enum clock_event_mode mode,
+			  struct clock_event_device *evt);
+static int hpet_next_event(unsigned long delta,
+			   struct clock_event_device *evt);
 
 /*
- * Stop the timers and reset the main counter.
+ * The hpet clock event device
  */
+struct clock_event_device hpet_clockevent = {
+	.name		= "hpet",
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.set_mode	= hpet_set_mode,
+	.set_next_event = hpet_next_event,
+	.shift		= 32,
+	.irq		= 0,
+};
+
+static void hpet_start_counter(void)
+{
+	unsigned long cfg = hpet_readl(HPET_CFG);
 
-	cfg = hpet_readl(HPET_CFG);
-	cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY);
+	cfg &= ~HPET_CFG_ENABLE;
 	hpet_writel(cfg, HPET_CFG);
 	hpet_writel(0, HPET_COUNTER);
 	hpet_writel(0, HPET_COUNTER + 4);
+	cfg |= HPET_CFG_ENABLE;
+	hpet_writel(cfg, HPET_CFG);
+}
 
-/*
- * Set up timer 0, as periodic with first interrupt to happen at hpet_tick,
- * and period also hpet_tick.
- */
-	if (hpet_use_timer) {
-		hpet_writel(HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL |
-		    HPET_TN_32BIT, HPET_T0_CFG);
-		hpet_writel(hpet_tick, HPET_T0_CMP); /* next interrupt */
-		hpet_writel(hpet_tick, HPET_T0_CMP); /* period */
-		cfg |= HPET_CFG_LEGACY;
-	}
-/*
- * Go!
- */
+static void hpet_enable_int(void)
+{
+	unsigned long cfg = hpet_readl(HPET_CFG);
 
-	cfg |= HPET_CFG_ENABLE;
+	cfg |= HPET_CFG_LEGACY;
 	hpet_writel(cfg, HPET_CFG);
+	hpet_legacy_int_enabled = 1;
+}
 
-	return 0;
+static void hpet_set_mode(enum clock_event_mode mode,
+			  struct clock_event_device *evt)
+{
+	unsigned long cfg, cmp, now;
+	uint64_t delta;
+
+	switch(mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * hpet_clockevent.mult;
+		delta >>= hpet_clockevent.shift;
+		now = hpet_readl(HPET_COUNTER);
+		cmp = now + (unsigned long) delta;
+		cfg = hpet_readl(HPET_T0_CFG);
+		cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC |
+		       HPET_TN_SETVAL | HPET_TN_32BIT;
+		hpet_writel(cfg, HPET_T0_CFG);
+		/*
+		 * The first write after writing TN_SETVAL to the
+		 * config register sets the counter value, the second
+		 * write sets the period.
+		 */
+		hpet_writel(cmp, HPET_T0_CMP);
+		udelay(1);
+		hpet_writel((unsigned int) delta, HPET_T0_CMP);
+		break;
+
+	case CLOCK_EVT_MODE_ONESHOT:
+		cfg = hpet_readl(HPET_T0_CFG);
+		cfg &= ~HPET_TN_PERIODIC;
+		cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
+		hpet_writel(cfg, HPET_T0_CFG);
+		break;
+
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		cfg = hpet_readl(HPET_T0_CFG);
+		cfg &= ~HPET_TN_ENABLE;
+		hpet_writel(cfg, HPET_T0_CFG);
+		break;
+	}
+}
+
+static int hpet_next_event(unsigned long delta,
+			   struct clock_event_device *evt)
+{
+	unsigned long cnt;
+
+	cnt = hpet_readl(HPET_COUNTER);
+	cnt += delta;
+	hpet_writel(cnt, HPET_T0_CMP);
+
+	return ((long)(hpet_readl(HPET_COUNTER) - cnt ) > 0);
 }
 
+/*
+ * Clock source related code
+ */
 static cycle_t read_hpet(void)
 {
-	return (cycle_t)hpet_readl(HPET_COUNTER);
+	return hpet_readl(HPET_COUNTER);
 }
 
 static cycle_t __vsyscall_fn vread_hpet(void)
@@ -136,10 +208,12 @@ struct clocksource clocksource_hpet = {
 int hpet_arch_init(void)
 {
 	unsigned int id;
+	uint64_t hpet_freq;
 	u64 tmp;
 
-	if (!hpet_address)
-		return -1;
+	if (!is_hpet_capable())
+		return 0;
+
 	set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
 	__set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE);
 
@@ -150,15 +224,31 @@ int hpet_arch_init(void)
 	id = hpet_readl(HPET_ID);
 
 	if (!(id & HPET_ID_VENDOR) || !(id & HPET_ID_NUMBER))
-		return -1;
+		return 0;
 
 	hpet_period = hpet_readl(HPET_PERIOD);
 	if (hpet_period < 100000 || hpet_period > 100000000)
-		return -1;
+		return 0;
+
+	/*
+	 * The period is a femto seconds value. We need to calculate the
+	 * scaled math multiplication factor for nanosecond to hpet tick
+	 * conversion.
+	 */
+	hpet_freq = 1000000000000000ULL;
+	do_div(hpet_freq, hpet_period);
+	hpet_clockevent.mult = div_sc((unsigned long) hpet_freq,
+				      NSEC_PER_SEC, 32);
+	/* Calculate the min / max delta */
+	hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
+							   &hpet_clockevent);
+	hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30,
+							   &hpet_clockevent);
 
 	hpet_tick = (FSEC_PER_TICK + hpet_period / 2) / hpet_period;
 
-	hpet_use_timer = (id & HPET_ID_LEGSUP);
+	/* Start the counter */
+	hpet_start_counter();
 
 	/*
 	 * hpet period is in femto seconds per cycle
@@ -176,12 +266,20 @@ int hpet_arch_init(void)
 	clocksource_hpet.mult = (u32)tmp;
 	clocksource_register(&clocksource_hpet);
 
-	return hpet_timer_stop_set_go(hpet_tick);
-}
+	hpet_use_timer = (id & HPET_ID_LEGSUP);
 
-int hpet_reenable(void)
-{
-	return hpet_timer_stop_set_go(hpet_tick);
+	if (hpet_use_timer) {
+		hpet_enable_int();
+		/*
+		 * Start hpet with the boot cpu mask and make it
+		 * global after the IO_APIC has been initialized.
+		 */
+		hpet_clockevent.cpumask = cpumask_of_cpu(0);
+		clockevents_register_device(&hpet_clockevent);
+		global_clock_event = &hpet_clockevent;
+		return 1;
+	}
+	return 0;
 }
 
 /*
@@ -265,7 +363,7 @@ static unsigned int hpet_t1_cmp; /* cach
 
 int is_hpet_enabled(void)
 {
-	return hpet_address != 0;
+	return is_hpet_capable() && hpet_legacy_int_enabled;
 }
 
 /*
--- linus-2.6.orig/arch/x86_64/Kconfig
+++ linus-2.6/arch/x86_64/Kconfig
@@ -28,6 +28,14 @@ config GENERIC_TIME
 	bool
 	default y
 
+config GENERIC_CLOCKEVENTS_BROADCAST
+	bool
+	default y
+
+config GENERIC_CLOCKEVENTS
+	bool
+	default y
+
 config GENERIC_TIME_VSYSCALL
 	bool
 	default y
--- linus-2.6.orig/arch/x86_64/kernel/apic.c
+++ linus-2.6/arch/x86_64/kernel/apic.c
@@ -26,6 +26,7 @@
 #include <linux/sysdev.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
+#include <linux/clockchips.h>
 
 #include <asm/atomic.h>
 #include <asm/smp.h>
@@ -62,6 +63,26 @@ static cpumask_t timer_interrupt_broadca
 /* Using APIC to generate smp_local_timer_interrupt? */
 int using_apic_timer __read_mostly = 0;
 
+
+static unsigned int calibration_result;
+
+static int lapic_next_event(unsigned long delta,
+			    struct clock_event_device *evt);
+static void lapic_timer_setup(enum clock_event_mode mode,
+			      struct clock_event_device *evt);
+
+static struct clock_event_device lapic_clockevent = {
+	.name		= "lapic",
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
+			| CLOCK_EVT_FEAT_C3STOP,
+	.shift		= 32,
+	.set_mode	= lapic_timer_setup,
+	.set_next_event	= lapic_next_event,
+	.rating		= 100,
+	.irq		= -1,
+};
+static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
+
 static void apic_pm_activate(void);
 
 void enable_NMI_through_LVT0 (void * dummy)
@@ -734,12 +755,15 @@ void __init init_apic_mappings(void)
 
 #define APIC_DIVISOR 16
 
-static void __setup_APIC_LVTT(unsigned int clocks)
+static void __setup_APIC_LVTT(unsigned int clocks, int oneshot)
 {
 	unsigned int lvtt_value, tmp_value;
 	int cpu = smp_processor_id();
 
-	lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
+	lvtt_value = LOCAL_TIMER_VECTOR;
+	if (!oneshot)
+		lvtt_value |= APIC_LVT_TIMER_PERIODIC;
+
 
 	if (cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask))
 		lvtt_value |= APIC_LVT_MASKED;
@@ -754,35 +778,24 @@ static void __setup_APIC_LVTT(unsigned i
 				& ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
 				| APIC_TDR_DIV_16);
 
-	apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
+	if (!oneshot)
+		apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
 }
 
-static void setup_APIC_timer(unsigned int clocks)
+static int lapic_next_event(unsigned long delta,
+			    struct clock_event_device *evt)
+{
+	apic_write(APIC_TMICT, delta);
+	return 0;
+}
+
+static void lapic_timer_setup(enum clock_event_mode mode,
+			      struct clock_event_device *evt)
 {
 	unsigned long flags;
 
 	local_irq_save(flags);
 
-	/* wait for irq slice */
- 	if (hpet_address && hpet_use_timer) {
- 		int trigger = hpet_readl(HPET_T0_CMP);
- 		while (hpet_readl(HPET_COUNTER) >= trigger)
- 			/* do nothing */ ;
- 		while (hpet_readl(HPET_COUNTER) <  trigger)
- 			/* do nothing */ ;
- 	} else {
-		int c1, c2;
-		outb_p(0x00, 0x43);
-		c2 = inb_p(0x40);
-		c2 |= inb_p(0x40) << 8;
-		do {
-			c1 = c2;
-			outb_p(0x00, 0x43);
-			c2 = inb_p(0x40);
-			c2 |= inb_p(0x40) << 8;
-		} while (c2 - c1 < 300);
-	}
-	__setup_APIC_LVTT(clocks);
 	/* Turn off PIT interrupt if we use APIC timer as main timer.
 	   Only works with the PM timer right now
 	   TBD fix it for HPET too. */
@@ -793,9 +806,33 @@ static void setup_APIC_timer(unsigned in
 		stop_timer_interrupt();
 		apic_runs_main_timer++;
 	}
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+	case CLOCK_EVT_MODE_ONESHOT:
+		__setup_APIC_LVTT(calibration_result,
+				  mode != CLOCK_EVT_MODE_PERIODIC);
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		disable_APIC_timer();
+		break;
+	}
+
 	local_irq_restore(flags);
 }
 
+
+static void __devinit setup_APIC_timer(void)
+{
+	struct clock_event_device *levt = &__get_cpu_var(lapic_events);
+
+	memcpy(levt, &lapic_clockevent, sizeof(*levt));
+	levt->cpumask = cpumask_of_cpu(smp_processor_id());
+
+	clockevents_register_device(levt);
+}
+
 /*
  * In this function we calibrate APIC bus clocks to the external
  * timer. Unfortunately we cannot use jiffies and the timer irq
@@ -815,12 +852,13 @@ static int __init calibrate_APIC_clock(v
 {
 	int apic, apic_start, tsc, tsc_start;
 	int result;
+	u64 wallclock_nsecs;
 	/*
 	 * Put whatever arbitrary (but long enough) timeout
 	 * value into the APIC clock, we just want to get the
 	 * counter running for calibration.
 	 */
-	__setup_APIC_LVTT(1000000000);
+	__setup_APIC_LVTT(1000000000, 0);
 
 	apic_start = apic_read(APIC_TMCCT);
 #ifdef CONFIG_X86_PM_TIMER
@@ -828,6 +866,8 @@ static int __init calibrate_APIC_clock(v
 		pmtimer_wait(5000);  /* 5ms wait */
 		apic = apic_read(APIC_TMCCT);
 		result = (apic_start - apic) * 1000L / 5;
+		printk("using pmtimer for lapic calibration\n");
+		wallclock_nsecs = 5000000;
 	} else
 #endif
 	{
@@ -841,6 +881,8 @@ static int __init calibrate_APIC_clock(v
 
 		result = (apic_start - apic) * 1000L * cpu_khz /
 					(tsc - tsc_start);
+		wallclock_nsecs = ((u64)tsc - (u64)tsc_start) * 1000000 / (u64)cpu_khz;
+
 	}
 	printk("result %d\n", result);
 
@@ -848,11 +890,22 @@ static int __init calibrate_APIC_clock(v
 	printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n",
 		result / 1000 / 1000, result / 1000 % 1000);
 
+
+
+
+	/* Calculate the scaled math multiplication factor */
+	lapic_clockevent.mult = div_sc(apic_start - apic, wallclock_nsecs, 32);
+
+	lapic_clockevent.max_delta_ns =
+		clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
+	printk("lapic max_delta_ns: %ld\n", lapic_clockevent.max_delta_ns);
+	lapic_clockevent.min_delta_ns =
+		clockevent_delta2ns(0xF, &lapic_clockevent);
+
+
 	return result * APIC_DIVISOR / HZ;
 }
 
-static unsigned int calibration_result;
-
 void __init setup_boot_APIC_clock (void)
 {
 	if (disable_apic_timer) { 
@@ -869,7 +922,7 @@ void __init setup_boot_APIC_clock (void)
 	/*
 	 * Now set up the timer for real.
 	 */
-	setup_APIC_timer(calibration_result);
+	setup_APIC_timer();
 
 	local_irq_enable();
 }
@@ -877,7 +930,7 @@ void __init setup_boot_APIC_clock (void)
 void __cpuinit setup_secondary_APIC_clock(void)
 {
 	local_irq_disable(); /* FIXME: Do we need this? --RR */
-	setup_APIC_timer(calibration_result);
+	setup_APIC_timer();
 	local_irq_enable();
 }
 
@@ -924,6 +977,13 @@ void switch_APIC_timer_to_ipi(void *cpum
 	    !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
 		disable_APIC_timer();
 		cpu_set(cpu, timer_interrupt_broadcast_ipi_mask);
+#ifdef CONFIG_HIGH_RES_TIMERS
+		printk("Disabling NO_HZ and high resolution timers "
+			"due to timer broadcasting\n");
+		for_each_possible_cpu(cpu)
+			per_cpu(lapic_events, cpu).features &=
+				~CLOCK_EVT_FEAT_ONESHOT;
+#endif
 	}
 }
 EXPORT_SYMBOL(switch_APIC_timer_to_ipi);
@@ -1008,6 +1068,9 @@ void smp_apic_timer_interrupt(struct pt_
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
+	int cpu = smp_processor_id();
+	struct clock_event_device *evt = &per_cpu(lapic_events, cpu);
+
 	/*
 	 * the NMI deadlock-detector uses this.
 	 */
@@ -1025,7 +1088,7 @@ void smp_apic_timer_interrupt(struct pt_
 	 */
 	exit_idle();
 	irq_enter();
-	smp_local_timer_interrupt();
+	evt->event_handler(evt);
 	irq_exit();
 	set_irq_regs(old_regs);
 }
--- linus-2.6.orig/include/asm-x86_64/hpet.h
+++ linus-2.6/include/asm-x86_64/hpet.h
@@ -56,8 +56,6 @@
 extern int is_hpet_enabled(void);
 extern int hpet_rtc_timer_init(void);
 extern int hpet_arch_init(void);
-extern int hpet_timer_stop_set_go(unsigned long tick);
-extern int hpet_reenable(void);
 extern unsigned int hpet_calibrate_tsc(void);
 
 extern int hpet_use_timer;

--

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

* [RFC PATCH 4/5] x86_64: prep idle loop for dynticks
  2007-03-31  8:31 [RFC PATCH 0/5] x86_64: enable clockevents and dynticks Chris Wright
                   ` (2 preceding siblings ...)
  2007-03-31  8:31 ` [RFC PATCH 3/5] x86_64: clockevents drivers Chris Wright
@ 2007-03-31  8:31 ` Chris Wright
  2007-03-31  8:31 ` [RFC PATCH 5/5] x86_64: enable dynticks Chris Wright
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 17+ messages in thread
From: Chris Wright @ 2007-03-31  8:31 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, john stultz, Andi Kleen; +Cc: linux-kernel

[-- Attachment #1: x86_64-dyntick-idle-updates.patch --]
[-- Type: text/plain, Size: 1107 bytes --]

Add tick_nohz_{stop,restart}_sched_tick to idle
loop in prepartion for turning on dynticks.  These
are just noops until NO_HZ is enabled in next patch.

Signed-off-by: Chris Wright <chrisw@sous-sol.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: john stultz <johnstul@us.ibm.com>
Cc: Andi Kleen <ak@suse.de>
---
 arch/x86_64/kernel/process.c |    3 +++
 1 file changed, 3 insertions(+)

--- linus-2.6.orig/arch/x86_64/kernel/process.c
+++ linus-2.6/arch/x86_64/kernel/process.c
@@ -36,6 +36,7 @@
 #include <linux/random.h>
 #include <linux/notifier.h>
 #include <linux/kprobes.h>
+#include <linux/tick.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -201,6 +202,7 @@ void cpu_idle (void)
 	current_thread_info()->status |= TS_POLLING;
 	/* endless idle loop with no priority at all */
 	while (1) {
+		tick_nohz_stop_sched_tick();
 		while (!need_resched()) {
 			void (*idle)(void);
 
@@ -227,6 +229,7 @@ void cpu_idle (void)
 			__exit_idle();
 		}
 
+		tick_nohz_restart_sched_tick();
 		preempt_enable_no_resched();
 		schedule();
 		preempt_disable();

--

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

* [RFC PATCH 5/5] x86_64: enable dynticks
  2007-03-31  8:31 [RFC PATCH 0/5] x86_64: enable clockevents and dynticks Chris Wright
                   ` (3 preceding siblings ...)
  2007-03-31  8:31 ` [RFC PATCH 4/5] x86_64: prep idle loop for dynticks Chris Wright
@ 2007-03-31  8:31 ` Chris Wright
  2007-03-31  9:23 ` [RFC PATCH 0/5] x86_64: enable clockevents and dynticks Ingo Molnar
  2007-04-01  9:22 ` Thomas Gleixner
  6 siblings, 0 replies; 17+ messages in thread
From: Chris Wright @ 2007-03-31  8:31 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, john stultz, Andi Kleen; +Cc: linux-kernel

[-- Attachment #1: x86_64-enable-dynticks.patch --]
[-- Type: text/plain, Size: 564 bytes --]

Everything is in place, so give the CONFIG_NO_HZ option.

Signed-off-by: Chris Wright <chrisw@sous-sol.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: john stultz <johnstul@us.ibm.com>
Cc: Andi Kleen <ak@suse.de>
---
 arch/x86_64/Kconfig |    2 ++
 1 file changed, 2 insertions(+)

--- linus-2.6.orig/arch/x86_64/Kconfig
+++ linus-2.6/arch/x86_64/Kconfig
@@ -134,6 +134,8 @@ source "init/Kconfig"
 
 menu "Processor type and features"
 
+source "kernel/time/Kconfig"
+
 choice
 	prompt "Subarchitecture Type"
 	default X86_PC

--

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

* Re: [RFC PATCH 0/5] x86_64: enable clockevents and dynticks
  2007-03-31  8:31 [RFC PATCH 0/5] x86_64: enable clockevents and dynticks Chris Wright
                   ` (4 preceding siblings ...)
  2007-03-31  8:31 ` [RFC PATCH 5/5] x86_64: enable dynticks Chris Wright
@ 2007-03-31  9:23 ` Ingo Molnar
  2007-03-31 16:36   ` Chris Wright
  2007-04-01  9:22 ` Thomas Gleixner
  6 siblings, 1 reply; 17+ messages in thread
From: Ingo Molnar @ 2007-03-31  9:23 UTC (permalink / raw)
  To: Chris Wright; +Cc: Thomas Gleixner, john stultz, Andi Kleen, linux-kernel


* Chris Wright <chrisw@sous-sol.org> wrote:

> This series converts x86_64 timers to clockevents drivers and then 
> enables dynticks.  There's some minor cleanups along the way.  The 
> lapic broadcast mechanism is untested, I'm sure it still needs work, 
> there's still some cruft in lapic_setup_timer.
> 
> This is just for comments at this point, now that it's working on my 
> test box in both NO_HZ=n and NO_HZ=n configurations (typically using 
> hpet).

hm, neat - did you take a look at the x86_64 clockevents code that is in 
-rt and that has been there for a year or so and has been tested quite 
extensively?

	Ingo

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

* Re: [RFC PATCH 0/5] x86_64: enable clockevents and dynticks
  2007-03-31  9:23 ` [RFC PATCH 0/5] x86_64: enable clockevents and dynticks Ingo Molnar
@ 2007-03-31 16:36   ` Chris Wright
  2007-03-31 16:46     ` Ingo Molnar
  0 siblings, 1 reply; 17+ messages in thread
From: Chris Wright @ 2007-03-31 16:36 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Chris Wright, Thomas Gleixner, john stultz, Andi Kleen, linux-kernel

* Ingo Molnar (mingo@elte.hu) wrote:
> * Chris Wright <chrisw@sous-sol.org> wrote:
> > This series converts x86_64 timers to clockevents drivers and then 
> > enables dynticks.  There's some minor cleanups along the way.  The 
> > lapic broadcast mechanism is untested, I'm sure it still needs work, 
> > there's still some cruft in lapic_setup_timer.
> > 
> > This is just for comments at this point, now that it's working on my 
> > test box in both NO_HZ=n and NO_HZ=n configurations (typically using 
> > hpet).
> 
> hm, neat - did you take a look at the x86_64 clockevents code that is in 
> -rt and that has been there for a year or so and has been tested quite 
> extensively?

Yes, that's what I started with.  It was only partially done, for example,
didn't have hpet done yet and didn't work well on my machine (hang
on boot).  As I dug at it, there was still more room for cleanups, etc.
Hence this, which has also been tested somewhat extensively as Jeremy
noted from my typo above...  Both NO_HZ=n _and_ NO_HZ=n ;-)

thanks,
-chris

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

* Re: [RFC PATCH 0/5] x86_64: enable clockevents and dynticks
  2007-03-31 16:36   ` Chris Wright
@ 2007-03-31 16:46     ` Ingo Molnar
  0 siblings, 0 replies; 17+ messages in thread
From: Ingo Molnar @ 2007-03-31 16:46 UTC (permalink / raw)
  To: Chris Wright; +Cc: Thomas Gleixner, john stultz, Andi Kleen, linux-kernel


* Chris Wright <chrisw@sous-sol.org> wrote:

> > hm, neat - did you take a look at the x86_64 clockevents code that 
> > is in -rt and that has been there for a year or so and has been 
> > tested quite extensively?
> 
> Yes, that's what I started with. [...]

ok :)

> [...]  It was only partially done, for example, didn't have hpet done 
> yet and didn't work well on my machine (hang on boot).  As I dug at 
> it, there was still more room for cleanups, etc. Hence this, which has 
> also been tested somewhat extensively as Jeremy noted from my typo 
> above...  Both NO_HZ=n _and_ NO_HZ=n ;-)

good :)

	Ingo

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

* Re: [RFC PATCH 0/5] x86_64: enable clockevents and dynticks
  2007-03-31  8:31 [RFC PATCH 0/5] x86_64: enable clockevents and dynticks Chris Wright
                   ` (5 preceding siblings ...)
  2007-03-31  9:23 ` [RFC PATCH 0/5] x86_64: enable clockevents and dynticks Ingo Molnar
@ 2007-04-01  9:22 ` Thomas Gleixner
  2007-04-01 18:54   ` Chris Wright
  2007-04-01 20:53   ` Andi Kleen
  6 siblings, 2 replies; 17+ messages in thread
From: Thomas Gleixner @ 2007-04-01  9:22 UTC (permalink / raw)
  To: Chris Wright; +Cc: Ingo Molnar, john stultz, Andi Kleen, linux-kernel

On Sat, 2007-03-31 at 01:31 -0700, Chris Wright wrote:
> This series converts x86_64 timers to clockevents drivers
> and then enables dynticks.  There's some minor cleanups along
> the way.  The lapic broadcast mechanism is untested, I'm sure it
> still needs work, there's still some cruft in lapic_setup_timer.
> 
> This is just for comments at this point, now that it's working
> on my test box in both NO_HZ=n and NO_HZ=n configurations (typically
> using hpet).

Have you checked, if we could share the code between i386 and x86_64 at
least for PIT and HPET. I'm not sure about the local APIC, but I think
it might be doable as well.

	tglx



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

* Re: [RFC PATCH 0/5] x86_64: enable clockevents and dynticks
  2007-04-01  9:22 ` Thomas Gleixner
@ 2007-04-01 18:54   ` Chris Wright
  2007-04-02 21:31     ` Thomas Gleixner
  2007-04-01 20:53   ` Andi Kleen
  1 sibling, 1 reply; 17+ messages in thread
From: Chris Wright @ 2007-04-01 18:54 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Chris Wright, Ingo Molnar, john stultz, Andi Kleen, linux-kernel

* Thomas Gleixner (tglx@linutronix.de) wrote:
> On Sat, 2007-03-31 at 01:31 -0700, Chris Wright wrote:
> > This series converts x86_64 timers to clockevents drivers
> > and then enables dynticks.  There's some minor cleanups along
> > the way.  The lapic broadcast mechanism is untested, I'm sure it
> > still needs work, there's still some cruft in lapic_setup_timer.
> > 
> > This is just for comments at this point, now that it's working
> > on my test box in both NO_HZ=n and NO_HZ=n configurations (typically
> > using hpet).
> 
> Have you checked, if we could share the code between i386 and x86_64 at
> least for PIT and HPET. I'm not sure about the local APIC, but I think
> it might be doable as well.

Yes, that's part of why I did some of the cleanups that way, so that we
could merge the two together later.

thanks,
-chris

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

* Re: [RFC PATCH 0/5] x86_64: enable clockevents and dynticks
  2007-04-01  9:22 ` Thomas Gleixner
  2007-04-01 18:54   ` Chris Wright
@ 2007-04-01 20:53   ` Andi Kleen
  2007-04-02  7:27     ` Thomas Gleixner
  1 sibling, 1 reply; 17+ messages in thread
From: Andi Kleen @ 2007-04-01 20:53 UTC (permalink / raw)
  To: tglx; +Cc: Chris Wright, Ingo Molnar, john stultz, linux-kernel


> Have you checked, if we could share the code between i386 and x86_64 at
> least for PIT and HPET. I'm not sure about the local APIC, but I think
> it might be doable as well.

Not for PIT. I don't want all the broken ancient hardware workarounds on x86-64.
HPET might be doable, but would need quite some work.

-Andi

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

* Re: [RFC PATCH 0/5] x86_64: enable clockevents and dynticks
  2007-04-01 20:53   ` Andi Kleen
@ 2007-04-02  7:27     ` Thomas Gleixner
  0 siblings, 0 replies; 17+ messages in thread
From: Thomas Gleixner @ 2007-04-02  7:27 UTC (permalink / raw)
  To: Andi Kleen; +Cc: Chris Wright, Ingo Molnar, john stultz, linux-kernel

On Sun, 2007-04-01 at 22:53 +0200, Andi Kleen wrote:
> > Have you checked, if we could share the code between i386 and x86_64 at
> > least for PIT and HPET. I'm not sure about the local APIC, but I think
> > it might be doable as well.
> 
> Not for PIT. I don't want all the broken ancient hardware workarounds on x86-64.

Err, what are you talking about ?

The clock events code in arch/i386/kernel/i8253.c does not have any
quirks. It's straight forward. The only quirk is in pit_read() and we
can simply make it depend on !64bit.

> HPET might be doable, but would need quite some work.

Right, but this is better spent than having two implementations of the
same thing around.

	tglx




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

* Re: [RFC PATCH 0/5] x86_64: enable clockevents and dynticks
  2007-04-01 18:54   ` Chris Wright
@ 2007-04-02 21:31     ` Thomas Gleixner
  2007-04-02 21:39       ` Chris Wright
  0 siblings, 1 reply; 17+ messages in thread
From: Thomas Gleixner @ 2007-04-02 21:31 UTC (permalink / raw)
  To: Chris Wright; +Cc: Ingo Molnar, john stultz, Andi Kleen, linux-kernel

On Sun, 2007-04-01 at 11:54 -0700, Chris Wright wrote:
> * Thomas Gleixner (tglx@linutronix.de) wrote:
> > On Sat, 2007-03-31 at 01:31 -0700, Chris Wright wrote:
> > > This series converts x86_64 timers to clockevents drivers
> > > and then enables dynticks.  There's some minor cleanups along
> > > the way.  The lapic broadcast mechanism is untested, I'm sure it
> > > still needs work, there's still some cruft in lapic_setup_timer.
> > > 
> > > This is just for comments at this point, now that it's working
> > > on my test box in both NO_HZ=n and NO_HZ=n configurations (typically
> > > using hpet).
> > 
> > Have you checked, if we could share the code between i386 and x86_64 at
> > least for PIT and HPET. I'm not sure about the local APIC, but I think
> > it might be doable as well.
> 
> Yes, that's part of why I did some of the cleanups that way, so that we
> could merge the two together later.

I'd prefer to get this done now. If we plug it in as is, the "merge
later" probably will never happen.

	tglx



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

* Re: [RFC PATCH 0/5] x86_64: enable clockevents and dynticks
  2007-04-02 21:31     ` Thomas Gleixner
@ 2007-04-02 21:39       ` Chris Wright
  2007-04-02 21:52         ` Thomas Gleixner
  0 siblings, 1 reply; 17+ messages in thread
From: Chris Wright @ 2007-04-02 21:39 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Chris Wright, Ingo Molnar, john stultz, Andi Kleen, linux-kernel

* Thomas Gleixner (tglx@linutronix.de) wrote:
> On Sun, 2007-04-01 at 11:54 -0700, Chris Wright wrote:
> > * Thomas Gleixner (tglx@linutronix.de) wrote:
> > > On Sat, 2007-03-31 at 01:31 -0700, Chris Wright wrote:
> > > > This series converts x86_64 timers to clockevents drivers
> > > > and then enables dynticks.  There's some minor cleanups along
> > > > the way.  The lapic broadcast mechanism is untested, I'm sure it
> > > > still needs work, there's still some cruft in lapic_setup_timer.
> > > > 
> > > > This is just for comments at this point, now that it's working
> > > > on my test box in both NO_HZ=n and NO_HZ=n configurations (typically
> > > > using hpet).
> > > 
> > > Have you checked, if we could share the code between i386 and x86_64 at
> > > least for PIT and HPET. I'm not sure about the local APIC, but I think
> > > it might be doable as well.
> > 
> > Yes, that's part of why I did some of the cleanups that way, so that we
> > could merge the two together later.
> 
> I'd prefer to get this done now. If we plug it in as is, the "merge
> later" probably will never happen.

that's fine, this is just RFC to see if there's obvious broken bits, etc.
also, i still need to do some split out of the pit.  it and hpet are nearly
identical though, so i don't noticing any issues with this.

the part i know is broken is lapic broadcast, so i'd like to fix that
up too.  trouble is, it's broken on vanilla too, so i'm not 100% sure
what i'm debugging yet.

thanks,
-chris

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

* Re: [RFC PATCH 0/5] x86_64: enable clockevents and dynticks
  2007-04-02 21:39       ` Chris Wright
@ 2007-04-02 21:52         ` Thomas Gleixner
  2007-04-02 22:17           ` Chris Wright
  0 siblings, 1 reply; 17+ messages in thread
From: Thomas Gleixner @ 2007-04-02 21:52 UTC (permalink / raw)
  To: Chris Wright; +Cc: Ingo Molnar, john stultz, Andi Kleen, linux-kernel

On Mon, 2007-04-02 at 14:39 -0700, Chris Wright wrote:
> > > Yes, that's part of why I did some of the cleanups that way, so that we
> > > could merge the two together later.
> > 
> > I'd prefer to get this done now. If we plug it in as is, the "merge
> > later" probably will never happen.
> 
> that's fine, this is just RFC to see if there's obvious broken bits, etc.
> also, i still need to do some split out of the pit.  it and hpet are nearly
> identical though, so i don't noticing any issues with this.

Ok.

> the part i know is broken is lapic broadcast, so i'd like to fix that
> up too.  trouble is, it's broken on vanilla too, so i'm not 100% sure
> what i'm debugging yet.

You need to remove switch_APIC_timer_to_ipi and counterpart so that the
clockevents broadcast gets control over broadcasting. This requires a
change in drivers/acpi/processor_idle.c as well

commit e9e2cdb412412326c4827fc78ba27f410d837e6e has the basic changes. 

	tglx



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

* Re: [RFC PATCH 0/5] x86_64: enable clockevents and dynticks
  2007-04-02 21:52         ` Thomas Gleixner
@ 2007-04-02 22:17           ` Chris Wright
  0 siblings, 0 replies; 17+ messages in thread
From: Chris Wright @ 2007-04-02 22:17 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Chris Wright, Ingo Molnar, john stultz, Andi Kleen, linux-kernel

* Thomas Gleixner (tglx@linutronix.de) wrote:
> On Mon, 2007-04-02 at 14:39 -0700, Chris Wright wrote:
> > the part i know is broken is lapic broadcast, so i'd like to fix that
> > up too.  trouble is, it's broken on vanilla too, so i'm not 100% sure
> > what i'm debugging yet.
> 
> You need to remove switch_APIC_timer_to_ipi and counterpart so that the
> clockevents broadcast gets control over broadcasting. This requires a
> change in drivers/acpi/processor_idle.c as well
> 
> commit e9e2cdb412412326c4827fc78ba27f410d837e6e has the basic changes. 

Yeah, I saw that, and while I didn't remove it yet, it shouldn't be
getting called from anywhere because of CONFIG_GENERIC_CLOCKEVENTS
being set.  In fact, acpi_propagate_timer_broadcast() does get called,
and all that does it drop me back to hpet because of C3.  But, I didn't add
DUMMY yet, and I must've missed smth else.  Some of that got a little
tangled into the nice calibration cleanup, which I didn't want to suck
in until I understood what I had broken ;-)

thanks,
-chris

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

end of thread, other threads:[~2007-04-02 22:24 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-03-31  8:31 [RFC PATCH 0/5] x86_64: enable clockevents and dynticks Chris Wright
2007-03-31  8:31 ` [RFC PATCH 1/5] x86_64: untangle asm/hpet.h from asm/timex.h Chris Wright
2007-03-31  8:31 ` [RFC PATCH 2/5] x86_64: drive set_rtc_mss from standalone timer Chris Wright
2007-03-31  8:31 ` [RFC PATCH 3/5] x86_64: clockevents drivers Chris Wright
2007-03-31  8:31 ` [RFC PATCH 4/5] x86_64: prep idle loop for dynticks Chris Wright
2007-03-31  8:31 ` [RFC PATCH 5/5] x86_64: enable dynticks Chris Wright
2007-03-31  9:23 ` [RFC PATCH 0/5] x86_64: enable clockevents and dynticks Ingo Molnar
2007-03-31 16:36   ` Chris Wright
2007-03-31 16:46     ` Ingo Molnar
2007-04-01  9:22 ` Thomas Gleixner
2007-04-01 18:54   ` Chris Wright
2007-04-02 21:31     ` Thomas Gleixner
2007-04-02 21:39       ` Chris Wright
2007-04-02 21:52         ` Thomas Gleixner
2007-04-02 22:17           ` Chris Wright
2007-04-01 20:53   ` Andi Kleen
2007-04-02  7:27     ` Thomas Gleixner

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.