Skip to contentSkip to conversation

High resolution timer updates and x86_64 support - V2

PATCH In review Thomas Gleixner 13 participants 52 messages Jun 16, 2007 – Jun 22, 2007

Subsystems (14)
lore
Share & tools
lore
#0 lore raw

cover High resolution timer updates and x86_64 support - V2

The following patch series contains:

- dyntick bugfixes for -mm (caused by the cpuidle changes in ACPI)

- updates and improvements to high resolution timer / dynticks

- high resolution timer / dynticks support for x86_64

The x86_64 support is based on an initial patch from Chris Wright. Thanks Chris !

The patch set has been tested in the -hrt and -rt trees for quite a while and the initial problems have been sorted out. Thanks to the folks from the PowerTop project for testing and feedback.

The -hrt tree at http://www.tglx.de/projects/hrtimers/2.6.22-rc4/ contains also an hpet force patch series from Venki Pallipadi, but I leave this up to Venki to send it mainline wards.

Changes since V1:

- simplified the idle breakage fixup

- fixed a resume bug (making the famous VAIO work again)

- added a clocksource settimeofday hook for PPC (Tony Breeds)

Thanks,

tglx

#1 lore raw

PATCH 1/25 NOHZ: Fix nox x86 dyntick idle handling

The cpuidle patches moved the tick nohz handling from irq_exit into the inner idle loop. The change is correct as it covers non interrupt based wakeups (e.g DMA) on x86 as well, but the move breaks ARM, SH and SPARC64.

Keep the original implementation and deselet the irq exit code for those architectures which have non irq idle wakeups.

This way the non affected architectures are not burdened with the extra changes in the idle implementation.

Cc Adam Belay <[email protected]>
Cc Len Brown <[email protected]>
Cc Dave Miller <[email protected]>
Cc Paul Mundt <[email protected]>
Cc Russell King <[email protected]>
---
 arch/i386/Kconfig |    4 ++++
 kernel/softirq.c  |    5 +++++
 2 files changed, 9 insertions(+)
arch/i386/Kconfig +4 -0
Index: linux-2.6.22-rc4-mm/arch/i386/Kconfig
===================================================================
@@ -31,6 +31,10 @@ config GENERIC_CLOCKEVENTS_BROADCAST
 	default y
 	depends on X86_LOCAL_APIC
 
+config NONIRQ_WAKEUP
+	bool
+	default y
+
 config LOCKDEP_SUPPORT
 	bool
 	default y
kernel/softirq.c +5 -0
Index: linux-2.6.22-rc4-mm/kernel/softirq.c
===================================================================
@@ -304,6 +304,11 @@ void irq_exit(void)
 	if (!in_interrupt() && local_softirq_pending())
 		invoke_softirq();
 
+#if defined(CONFIG_NO_HZ) && !defined(CONFIG_NONIRQ_WAKEUP)
+	/* Make sure that timer wheel updates are propagated */
+	if (!in_interrupt() && idle_cpu(smp_processor_id()) && !need_resched())
+		tick_nohz_stop_sched_tick();a
+#endif
 	preempt_enable_no_resched();
 }
 
#2 lore raw

Re: [patch-mm 01/25] NOHZ: Fix nox x86 dyntick idle handling

kernel/softirq.c void irq_exit(void) · line 313

Quoted 7 lines · Thomas Gleixner
kernel/softirq.c +5 -0
+#if defined(CONFIG_NO_HZ) && !defined(CONFIG_NONIRQ_WAKEUP)
+	/* Make sure that timer wheel updates are propagated */
+	if (!in_interrupt() && idle_cpu(smp_processor_id()) && !need_resched())
+		tick_nohz_stop_sched_tick();a
+#endif
 	preempt_enable_no_resched();
 }

The bit above breaks the build for a CONFIG_NO_HZ build without CONFIG_NONIRQ_WAKEUP -- please remove the extra "a" after tick_nohz_stop_sched_tick(); before applying this.

Regards,
bero

#3 lore raw

Re: [patch-mm 01/25] NOHZ: Fix nox x86 dyntick idle handling

Quoted 13 lines · Bernhard Rosenkraenzer

Review

Quoted 7 lines · Thomas Gleixner
(quoted diff) +5 -0
+#if defined(CONFIG_NO_HZ) && !defined(CONFIG_NONIRQ_WAKEUP)
+	/* Make sure that timer wheel updates are propagated */
+	if (!in_interrupt() && idle_cpu(smp_processor_id()) && !need_resched())
+		tick_nohz_stop_sched_tick();a
+#endif
 	preempt_enable_no_resched();
 }

The bit above breaks the build for a CONFIG_NO_HZ build without CONFIG_NONIRQ_WAKEUP -- please remove the extra "a" after tick_nohz_stop_sched_tick(); before applying this.

Oops. Must have happened when I edited the mailbox. Replacement patch below:

tglx

--------------------->

Subject: NOHZ: Fix nox x86 dyntick idle handling

The cpuidle patches moved the tick nohz handling from irq_exit into the inner idle loop. The change is correct as it covers non interrupt based wakeups (e.g DMA) on x86 as well, but the move breaks ARM, SH and SPARC64.

Keep the original implementation and deselet the irq exit code for those architectures which have no irq idle wakeups.

This way the non affected architectures are not burdened with the extra changes in the idle implementation.

Cc Adam Belay <[email protected]>
Cc Len Brown <[email protected]>
Cc Dave Miller <[email protected]>
Cc Paul Mundt <[email protected]>
Cc Russell King <[email protected]>
---
 arch/i386/Kconfig |    4 ++++
 kernel/softirq.c  |    5 +++++
 2 files changed, 9 insertions(+)
arch/i386/Kconfig +4 -0
Index: linux-2.6.22-rc4-mm/arch/i386/Kconfig
===================================================================
@@ -31,6 +31,10 @@ config GENERIC_CLOCKEVENTS_BROADCAST
 	default y
 	depends on X86_LOCAL_APIC
 
+config NONIRQ_WAKEUP
+	bool
+	default y
+
 config LOCKDEP_SUPPORT
 	bool
 	default y
kernel/softirq.c +5 -0
Index: linux-2.6.22-rc4-mm/kernel/softirq.c
===================================================================
@@ -304,6 +304,11 @@ void irq_exit(void)
 	if (!in_interrupt() && local_softirq_pending())
 		invoke_softirq();
 
+#if defined(CONFIG_NO_HZ) && !defined(CONFIG_NONIRQ_WAKEUP)
+	/* Make sure that timer wheel updates are propagated */
+	if (!in_interrupt() && idle_cpu(smp_processor_id()) && !need_resched())
+		tick_nohz_stop_sched_tick();
+#endif
 	preempt_enable_no_resched();
 }
 
#4 lore raw

PATCH 2/25 ACPI: Move timer broadcast and pmtimer access before C3 arbiter shutdown

In reply to Thomas Gleixner

From: Udo A. Steinberg <[email protected]>

The chipset doc for IHC4 tells us:

1.In general, software should not attempt any non-posted accesses during arbiter disable except to the ICH4's power management registers. This implies that interrupt handlers for any unmasked hardware interrupts and SMI/NMI should check ARB_DIS status before reading from ICH devices.

So it's not a good idea to access ICH devices after arbiter shut down.

---
 drivers/acpi/processor_idle.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/acpi/processor_idle.c +6 -1
Index: linux-2.6.22-rc4-mm/drivers/acpi/processor_idle.c
===================================================================
@@ -978,6 +978,12 @@ static int acpi_idle_enter_c3(struct cpu
 		return 0;
 	}
 
+	/*
+	 * Must be done before busmaster disable as we might need to
+	 * access HPET !
+	 */
+	acpi_state_timer_broadcast(pr, cx, 1);
+
 	/* disable bus master */
 	if (pr->flags.bm_check) {
 		spin_lock(&c3_lock);
@@ -997,7 +1003,6 @@ static int acpi_idle_enter_c3(struct cpu
 
 	/* Get start time (ticks) */
 	t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
-	acpi_state_timer_broadcast(pr, cx, 1);
 	acpi_idle_do_entry(cx);
 	t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
 
#5 lore raw

PATCH 3/25 Clockevents remove prototypes of removed functions

In reply to Thomas Gleixner
---
 include/linux/clockchips.h |    4 ----
 1 file changed, 4 deletions(-)
include/linux/clockchips.h +0 -4
Index: linux-2.6.22-rc4-mm/include/linux/clockchips.h
===================================================================
@@ -119,10 +119,6 @@ extern void clockevents_register_device(
 
 extern void clockevents_exchange_device(struct clock_event_device *old,
 					struct clock_event_device *new);
-extern
-struct clock_event_device *clockevents_request_device(unsigned int features,
-						      cpumask_t cpumask);
-extern void clockevents_release_device(struct clock_event_device *dev);
 extern void clockevents_set_mode(struct clock_event_device *dev,
 				 enum clock_event_mode mode);
 extern int clockevents_register_notifier(struct notifier_block *nb);
#6 lore raw

PATCH 4/25 Timekeeping: Fixup shadow variable argument

In reply to Thomas Gleixner

clocksource_adjust() has a clock argument, which shadows the file global clock variable. Fix this up.

---
 kernel/time/timekeeping.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/time/timekeeping.c +2 -2
Index: linux-2.6.22-rc4-mm/kernel/time/timekeeping.c
===================================================================
@@ -401,7 +401,7 @@ static __always_inline int clocksource_b
  * this is optimized for the most common adjustments of -1,0,1,
  * for other values we can do a bit more work.
  */
-static void clocksource_adjust(struct clocksource *clock, s64 offset)
+static void clocksource_adjust(s64 offset)
 {
 	s64 error, interval = clock->cycle_interval;
 	int adj;
@@ -476,7 +476,7 @@ void update_wall_time(void)
 	}
 
 	/* correct the clock when NTP error is too big */
-	clocksource_adjust(clock, offset);
+	clocksource_adjust(offset);
 
 	/* store full nanoseconds into xtime */
 	xtime.tv_nsec = (s64)clock->xtime_nsec >> clock->shift;
#7 lore raw

PATCH 5/25 timer.c cleanup recently introduced whitespace damage

In reply to Thomas Gleixner
---
 kernel/timer.c |   24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)
kernel/timer.c +12 -12
Index: linux-2.6.22-rc4-mm/kernel/timer.c
===================================================================
@@ -103,14 +103,14 @@ static inline tvec_base_t *tbase_get_bas
 static inline void timer_set_deferrable(struct timer_list *timer)
 {
 	timer->base = ((tvec_base_t *)((unsigned long)(timer->base) |
-	                               TBASE_DEFERRABLE_FLAG));
+				       TBASE_DEFERRABLE_FLAG));
 }
 
 static inline void
 timer_set_base(struct timer_list *timer, tvec_base_t *new_base)
 {
 	timer->base = (tvec_base_t *)((unsigned long)(new_base) |
-	                              tbase_get_deferrable(timer->base));
+				      tbase_get_deferrable(timer->base));
 }
 
 /**
@@ -445,10 +445,10 @@ EXPORT_SYMBOL(__mod_timer);
 void add_timer_on(struct timer_list *timer, int cpu)
 {
 	tvec_base_t *base = per_cpu(tvec_bases, cpu);
-  	unsigned long flags;
+	unsigned long flags;
 
 	timer_stats_timer_set_start_info(timer);
-  	BUG_ON(timer_pending(timer) || !timer->function);
+	BUG_ON(timer_pending(timer) || !timer->function);
 	spin_lock_irqsave(&base->lock, flags);
 	timer_set_base(timer, base);
 	internal_add_timer(base, timer);
@@ -627,7 +627,7 @@ static inline void __run_timers(tvec_bas
 	while (time_after_eq(jiffies, base->timer_jiffies)) {
 		struct list_head work_list;
 		struct list_head *head = &work_list;
- 		int index = base->timer_jiffies & TVR_MASK;
+		int index = base->timer_jiffies & TVR_MASK;
 
 		/*
 		 * Cascade timers:
@@ -644,8 +644,8 @@ static inline void __run_timers(tvec_bas
 			unsigned long data;
 
 			timer = list_first_entry(head, struct timer_list,entry);
- 			fn = timer->function;
- 			data = timer->data;
+			fn = timer->function;
+			data = timer->data;
 
 			timer_stats_account_timer(timer);
 
@@ -689,8 +689,8 @@ static unsigned long __next_timer_interr
 	index = slot = timer_jiffies & TVR_MASK;
 	do {
 		list_for_each_entry(nte, base->tv1.vec + slot, entry) {
- 			if (tbase_get_deferrable(nte->base))
- 				continue;
+			if (tbase_get_deferrable(nte->base))
+				continue;
 
 			found = 1;
 			expires = nte->expires;
@@ -834,7 +834,7 @@ void update_process_times(int user_tick)
 	if (rcu_pending(cpu))
 		rcu_check_callbacks(cpu, user_tick);
 	scheduler_tick();
- 	run_posix_cpu_timers(p);
+	run_posix_cpu_timers(p);
 }
 
 /*
@@ -909,7 +909,7 @@ static inline void update_times(unsigned
 	update_wall_time();
 	calc_load(ticks);
 }
-  
+
 /*
  * The 64-bit jiffies value is not atomic - you MUST NOT read it
  * without sampling the sequence number in xtime_lock.
@@ -1105,7 +1105,7 @@ asmlinkage long sys_gettid(void)
 /**
  * do_sysinfo - fill in sysinfo struct
  * @info: pointer to buffer to fill
- */ 
+ */
 int do_sysinfo(struct sysinfo *info)
 {
 	unsigned long mem_total, sav_total;
#8 lore raw

PATCH 6/25 clockevents: Fix resume logic

In reply to Thomas Gleixner

We need to make sure, that the clockevent devices are resumed, before the tick is resumed. The current resume logic does not guarantee this.

Add CLOCK_EVT_MODE_RESUME and call the set mode functions of the clock event devices before resuming the tick / oneshot functionality.

Fixup the existing users.

This removes the sysfs entry for the HPET, which is now controlled by the clockevents resume code.

---
 arch/arm/mach-davinci/time.c      |    2 +
 arch/arm/mach-imx/time.c          |    1 
 arch/arm/mach-ixp4xx/common.c     |    2 +
 arch/arm/mach-omap1/time.c        |    1 
 arch/arm/plat-omap/timer32k.c     |    2 +
 arch/i386/kernel/apic.c           |    3 +
 arch/i386/kernel/hpet.c           |   71 ++------------------------------------
 arch/i386/kernel/i8253.c          |   26 ++++++-------
 arch/i386/kernel/vmiclock.c       |    1 
 arch/i386/xen/time.c              |    1 
 arch/sh/kernel/timers/timer-tmu.c |    1 
 arch/sparc64/kernel/time.c        |    1 
 include/linux/clockchips.h        |    1 
 kernel/time/tick-broadcast.c      |    6 ++-
 kernel/time/tick-common.c         |   16 +++++---
 15 files changed, 47 insertions(+), 88 deletions(-)
arch/i386/kernel/apic.c +3 -0
Index: linux-2.6.22-rc4-mm/arch/i386/kernel/apic.c
===================================================================
@@ -263,6 +263,9 @@ static void lapic_timer_setup(enum clock
 		v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
 		apic_write_around(APIC_LVTT, v);
 		break;
+	case CLOCK_EVT_MODE_RESUME:
+		/* Nothing to do here */
+		break;
 	}
 
 	local_irq_restore(flags);
arch/i386/kernel/hpet.c +5 -66

92 lines not on this page · raw message

arch/i386/kernel/i8253.c +12 -14
Index: linux-2.6.22-rc4-mm/arch/i386/kernel/i8253.c
===================================================================
@@ -3,11 +3,11 @@
  *
  */
 #include <linux/clockchips.h>
-#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/jiffies.h>
-#include <linux/sysdev.h>
 #include <linux/module.h>
-#include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <asm/smp.h>
 #include <asm/delay.h>
@@ -42,26 +42,24 @@ static void init_pit_timer(enum clock_ev
 	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 */
-		udelay(10);
 		outb(LATCH >> 8 , PIT_CH0);	/* MSB */
 		break;
 
-	/*
-	 * Avoid unnecessary state transitions, as it confuses
-	 * Geode / Cyrix based boxen.
-	 */
 	case CLOCK_EVT_MODE_SHUTDOWN:
-		if (evt->mode == CLOCK_EVT_MODE_UNUSED)
-			break;
 	case CLOCK_EVT_MODE_UNUSED:
-		if (evt->mode == CLOCK_EVT_MODE_SHUTDOWN)
-			break;
+		outb_p(0x30, PIT_MODE);
+		outb_p(0, PIT_CH0);	/* LSB */
+		outb_p(0, PIT_CH0);	/* MSB */
+		break;
+
 	case CLOCK_EVT_MODE_ONESHOT:
 		/* One shot setup */
 		outb_p(0x38, PIT_MODE);
-		udelay(10);
+		break;
+
+	case CLOCK_EVT_MODE_RESUME:
+		/* Nothing to do here */
 		break;
 	}
 	spin_unlock_irqrestore(&i8253_lock, flags);
include/linux/clockchips.h +1 -0
Index: linux-2.6.22-rc4-mm/include/linux/clockchips.h
===================================================================
@@ -23,6 +23,7 @@ enum clock_event_mode {
 	CLOCK_EVT_MODE_SHUTDOWN,
 	CLOCK_EVT_MODE_PERIODIC,
 	CLOCK_EVT_MODE_ONESHOT,
+	CLOCK_EVT_MODE_RESUME,
 };
 
 /* Clock event notification values */
kernel/time/tick-broadcast.c +4 -2
Index: linux-2.6.22-rc4-mm/kernel/time/tick-broadcast.c
===================================================================
@@ -49,7 +49,7 @@ cpumask_t *tick_get_broadcast_mask(void)
  */
 static void tick_broadcast_start_periodic(struct clock_event_device *bc)
 {
-	if (bc && bc->mode == CLOCK_EVT_MODE_SHUTDOWN)
+	if (bc)
 		tick_setup_periodic(bc, 1);
 }
 
@@ -299,7 +299,7 @@ void tick_suspend_broadcast(void)
 	spin_lock_irqsave(&tick_broadcast_lock, flags);
 
 	bc = tick_broadcast_device.evtdev;
-	if (bc && tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
+	if (bc)
 		clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
 
 	spin_unlock_irqrestore(&tick_broadcast_lock, flags);
@@ -316,6 +316,8 @@ int tick_resume_broadcast(void)
 	bc = tick_broadcast_device.evtdev;
 
 	if (bc) {
+		clockevents_set_mode(bc, CLOCK_EVT_MODE_RESUME);
+
 		switch (tick_broadcast_device.mode) {
 		case TICKDEV_MODE_PERIODIC:
 			if(!cpus_empty(tick_broadcast_mask))
kernel/time/tick-common.c +10 -6
Index: linux-2.6.22-rc4-mm/kernel/time/tick-common.c
===================================================================
@@ -318,12 +318,17 @@ static void tick_resume(void)
 {
 	struct tick_device *td = &__get_cpu_var(tick_cpu_device);
 	unsigned long flags;
+	int broadcast = tick_resume_broadcast();
 
 	spin_lock_irqsave(&tick_device_lock, flags);
-	if (td->mode == TICKDEV_MODE_PERIODIC)
-		tick_setup_periodic(td->evtdev, 0);
-	else
-		tick_resume_oneshot();
+	clockevents_set_mode(td->evtdev, CLOCK_EVT_MODE_RESUME);
+
+	if (!broadcast) {
+		if (td->mode == TICKDEV_MODE_PERIODIC)
+			tick_setup_periodic(td->evtdev, 0);
+		else
+			tick_resume_oneshot();
+	}
 	spin_unlock_irqrestore(&tick_device_lock, flags);
 }
 
@@ -360,8 +365,7 @@ static int tick_notify(struct notifier_b
 		break;
 
 	case CLOCK_EVT_NOTIFY_RESUME:
-		if (!tick_resume_broadcast())
-			tick_resume();
+		tick_resume();
 		break;
 
 	default:
arch/arm/mach-davinci/time.c +2 -0
Index: linux-2.6.22-rc4-mm/arch/arm/mach-davinci/time.c
===================================================================
@@ -285,6 +285,8 @@ static void davinci_set_mode(enum clock_
 	case CLOCK_EVT_MODE_SHUTDOWN:
 		t->opts = TIMER_OPTS_DISABLED;
 		break;
+	case CLOCK_EVT_MODE_RESUME:
+		break;
 	}
 }
 
arch/arm/mach-imx/time.c +1 -0
Index: linux-2.6.22-rc4-mm/arch/arm/mach-imx/time.c
===================================================================
@@ -159,6 +159,7 @@ static void imx_set_mode(enum clock_even
 		break;
 	case CLOCK_EVT_MODE_SHUTDOWN:
 	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_RESUME:
 		/* Left event sources disabled, no more interrupts appears */
 		break;
 	}
arch/arm/mach-ixp4xx/common.c +2 -0
Index: linux-2.6.22-rc4-mm/arch/arm/mach-ixp4xx/common.c
===================================================================
@@ -459,6 +459,8 @@ static void ixp4xx_set_mode(enum clock_e
 	default:
 		osrt = opts = 0;
 		break;
+	case CLOCK_EVT_MODE_RESUME:
+		break;
 	}
 
 	*IXP4XX_OSRT1 = osrt | opts;
arch/arm/mach-omap1/time.c +1 -0
Index: linux-2.6.22-rc4-mm/arch/arm/mach-omap1/time.c
===================================================================
@@ -156,6 +156,7 @@ static void omap_mpu_set_mode(enum clock
 		break;
 	case CLOCK_EVT_MODE_UNUSED:
 	case CLOCK_EVT_MODE_SHUTDOWN:
+	case CLOCK_EVT_MODE_RESUME:
 		break;
 	}
 }
arch/arm/plat-omap/timer32k.c +2 -0
Index: linux-2.6.22-rc4-mm/arch/arm/plat-omap/timer32k.c
===================================================================
@@ -156,6 +156,8 @@ static void omap_32k_timer_set_mode(enum
 	case CLOCK_EVT_MODE_SHUTDOWN:
 		omap_32k_timer_stop();
 		break;
+	case CLOCK_EVT_MODE_RESUME:
+		break;
 	}
 }
 
arch/i386/kernel/vmiclock.c +1 -0
Index: linux-2.6.22-rc4-mm/arch/i386/kernel/vmiclock.c
===================================================================
@@ -142,6 +142,7 @@ static void vmi_timer_set_mode(enum cloc
 
 	switch (mode) {
 	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_RESUME:
 		break;
 	case CLOCK_EVT_MODE_PERIODIC:
 		cycles_per_hz = vmi_timer_ops.get_cycle_frequency();
arch/i386/xen/time.c +1 -0
Index: linux-2.6.22-rc4-mm/arch/i386/xen/time.c
===================================================================
@@ -407,6 +407,7 @@ static void xen_timerop_set_mode(enum cl
 		break;
 
 	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_RESUME:
 		break;
 
 	case CLOCK_EVT_MODE_UNUSED:
arch/sh/kernel/timers/timer-tmu.c +1 -0
Index: linux-2.6.22-rc4-mm/arch/sh/kernel/timers/timer-tmu.c
===================================================================
@@ -80,6 +80,7 @@ static void tmu_set_mode(enum clock_even
 		break;
 	case CLOCK_EVT_MODE_UNUSED:
 	case CLOCK_EVT_MODE_SHUTDOWN:
+	case CLOCK_EVT_MODE_RESUME:
 		break;
 	}
 }
arch/sparc64/kernel/time.c +1 -0
Index: linux-2.6.22-rc4-mm/arch/sparc64/kernel/time.c
===================================================================
@@ -938,6 +938,7 @@ static void sparc64_timer_setup(enum clo
 {
 	switch (mode) {
 	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_RESUME:
 		break;
 
 	case CLOCK_EVT_MODE_SHUTDOWN:
#9 lore raw

Separate arch patching (Re: [patch-mm 06/25] clockevents: Fix resume logic)

* From: Thomas Gleixner

[]

Quoted 5 lines

Fixup the existing users.

This removes the sysfs entry for the HPET, which is now controlled by the clockevents resume code.

Quoted 8 lines
---
 arch/arm/mach-davinci/time.c      |    2 +
 arch/arm/mach-imx/time.c          |    1 
 arch/arm/mach-ixp4xx/common.c     |    2 +
 arch/arm/mach-omap1/time.c        |    1 
 arch/arm/plat-omap/timer32k.c     |    2 +

Testers and users are most likely to run one particular arch on one particular test bench. If individual patches are arch separated, i think bisecting will be a little bit easier.

Thus, i would like to propose separate arch patching (x86_64/i386 mainly).

Is it possible to do that? (And even set such check in ``checkpatch''?)

You would say, why? Because current kbuild/kconfig support of builds for whole tree.

That's because to make download, build, test and debug particular arch more easily, i'm trying to re-think and re-do some kbuild parts. With minimum set of files, downloaded with git one can spend less time/bandwidth for starting testing.

Quoted 5 lines
 arch/i386/kernel/apic.c           |    3 +
 arch/i386/kernel/hpet.c           |   71 ++------------------------------------
 arch/i386/kernel/i8253.c          |   26 ++++++-------
 arch/i386/kernel/vmiclock.c       |    1 
 arch/i386/xen/time.c              |    1 

Opinions?

Quoted 2 lines
 arch/sh/kernel/timers/timer-tmu.c |    1 
 arch/sparc64/kernel/time.c        |    1 

____

#10 lore raw

Re: Separate arch patching (Re: [patch-mm 06/25] clockevents: Fix resume logic)

Oleg,

Quoted 5 lines · Oleg Verych
Quoted 1 line
 arch/arm/plat-omap/timer32k.c     |    2 +

Testers and users are most likely to run one particular arch on one particular test bench. If individual patches are arch separated, i think bisecting will be a little bit easier.

No it is not. See below.

Quoted 1 line

Thus, i would like to propose separate arch patching (x86_64/i386 mainly).

This change adds an enum entry in a generic header file. _ALL_ users of clock events have a switch(this_changed_enum) in the set_mode() function. _ALL_ of them will spit warnings and some of them will even break, when the fix up is not done in one go.

Quoted 1 line

Is it possible to do that? (And even set such check in ``checkpatch''?)

It's possible, but results in an commit which will affect bisecting. I'm not going to send a patch which knowingly breaks bisecting either at compile or at run time.

Quoted 7 lines

You would say, why? Because current kbuild/kconfig support of builds for whole tree.

That's because to make download, build, test and debug particular arch more easily, i'm trying to re-think and re-do some kbuild parts. With minimum set of files, downloaded with git one can spend less time/bandwidth for starting testing.

Oh, well. That's going to be an interesting feature for git and the result will be published kernel trees with a total delta of 40MB against mainline, because someone tweaked the stuff in a way that it contains only the relevant files for a particular sub architecture. Embedded folks do this already and it makes it extremely hard to do efficient trouble shooting on such crippled trees. No thanks.

If we would still have 9600 Baud modem connections I would understand that, but git is really effective since packing was added, so this argument is more or less an academic exercise.

tglx

#11 lore raw

PATCH 7/25 Tick management: spread timer interrupt

In reply to Thomas Gleixner

From: john stultz <[email protected]>

After discussing w/ Thomas over IRC, it seems the issue is the sched tick fires on every cpu at the same time, causing extra lock contention.

This smaller change, adds an extra offset per cpu so the ticks don't line up. This patch also drops the idle latency from 40us down to under 20us.

---
 kernel/time/tick-sched.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
kernel/time/tick-sched.c +6 -1
Index: linux-2.6.22-rc4-mm/kernel/time/tick-sched.c
===================================================================
@@ -573,6 +573,7 @@ void tick_setup_sched_timer(void)
 {
 	struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
 	ktime_t now = ktime_get();
+	u64 offset;
 
 	/*
 	 * Emulate tick processing via per-CPU hrtimers:
@@ -581,8 +582,12 @@ void tick_setup_sched_timer(void)
 	ts->sched_timer.function = tick_sched_timer;
 	ts->sched_timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ;
 
-	/* Get the next period */
+	/* Get the next period (per cpu)*/
 	ts->sched_timer.expires = tick_init_jiffy_update();
+	offset = ktime_to_ns(tick_period) >> 1;
+	do_div(offset, NR_CPUS);
+	offset *= smp_processor_id();
+	ts->sched_timer.expires = ktime_add_ns(ts->sched_timer.expires, offset);
 
 	for (;;) {
 		hrtimer_forward(&ts->sched_timer, now, tick_period);
#12 lore raw

PATCH 8/25 i386: PIT stop only, when in periodic or oneshot mode

In reply to Thomas Gleixner

The patch is necessary on one of my boxen, where programming the stop sequence twice leads to PIT malfunction.

Sigh !

---
 arch/i386/kernel/i8253.c |    9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)
arch/i386/kernel/i8253.c +6 -3
Index: linux-2.6.22-rc4-mm/arch/i386/kernel/i8253.c
===================================================================
@@ -48,9 +48,12 @@ static void init_pit_timer(enum clock_ev
 
 	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 */
+		if (evt->mode == CLOCK_EVT_MODE_PERIODIC ||
+		    evt->mode == CLOCK_EVT_MODE_ONESHOT) {
+			outb_p(0x30, PIT_MODE);
+			outb_p(0, PIT_CH0);
+			outb_p(0, PIT_CH0);
+		}
 		break;
 
 	case CLOCK_EVT_MODE_ONESHOT:
#13 lore raw

PATCH 9/25 clockevents: Fix device replacement

In reply to Thomas Gleixner

When a device is replaced by a better rated device, then the broadcast mode needs to be evaluated again. When the new device has no requirement for broadcasting, then the broadcast bits for the CPU must be cleared.

---
 kernel/time/tick-broadcast.c |   29 ++++++++++++++++++++++++++++-
 1 file changed, 28 insertions(+), 1 deletion(-)
kernel/time/tick-broadcast.c +28 -1
Index: linux-2.6.22-rc4-mm/kernel/time/tick-broadcast.c
===================================================================
@@ -31,6 +31,12 @@ struct tick_device tick_broadcast_device
 static cpumask_t tick_broadcast_mask;
 static DEFINE_SPINLOCK(tick_broadcast_lock);
 
+#ifdef CONFIG_TICK_ONESHOT
+static void tick_broadcast_clear_oneshot(int cpu);
+#else
+static inline void tick_broadcast_clear_oneshot(int cpu) { }
+#endif
+
 /*
  * Debugging: see timer_list.c
  */
@@ -99,8 +105,19 @@ int tick_device_uses_broadcast(struct cl
 		cpu_set(cpu, tick_broadcast_mask);
 		tick_broadcast_start_periodic(tick_broadcast_device.evtdev);
 		ret = 1;
-	}
+	} else {
+		/*
+		 * When the new device is not affected by the stop
+		 * feature and the cpu is marked in the broadcast mask
+		 * then clear the broadcast bit.
+		 */
+		if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) {
+			int cpu = smp_processor_id();
 
+			cpu_clear(cpu, tick_broadcast_mask);
+			tick_broadcast_clear_oneshot(cpu);
+		}
+	}
 	spin_unlock_irqrestore(&tick_broadcast_lock, flags);
 	return ret;
 }
@@ -487,6 +504,16 @@ out:
 	spin_unlock_irqrestore(&tick_broadcast_lock, flags);
 }
 
+/*
+ * Reset the one shot broadcast for a cpu
+ *
+ * Called with tick_broadcast_lock held
+ */
+static void tick_broadcast_clear_oneshot(int cpu)
+{
+	cpu_clear(cpu, tick_broadcast_oneshot_mask);
+}
+
 /**
  * tick_broadcast_setup_highres - setup the broadcast device for highres
  */
#14 lore raw

PATCH 10/25 highres: Improve debug output

In reply to Thomas Gleixner

From: Ingo Molnar <[email protected]>

Add some more debug information to the hrtimer and clock events code.

---
 arch/i386/kernel/apic.c    |    3 +++
 kernel/hrtimer.c           |    5 ++++-
 kernel/time/tick-oneshot.c |   15 ++++++++++++++-
 3 files changed, 21 insertions(+), 2 deletions(-)
arch/i386/kernel/apic.c +3 -0
Index: linux-2.6.22-rc4-mm/arch/i386/kernel/apic.c
===================================================================
@@ -524,6 +524,9 @@ void __init setup_boot_APIC_clock(void)
 		 */
 		if (nmi_watchdog != NMI_IO_APIC)
 			lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
+		else
+			printk(KERN_WARNING "APIC timer registered as dummy,"
+			       " due to nmi_watchdog=1!\n");
 	}
 
 	/* Setup the lapic or request the broadcast */
kernel/hrtimer.c +4 -1
Index: linux-2.6.22-rc4-mm/kernel/hrtimer.c
===================================================================
@@ -558,7 +558,8 @@ static inline int hrtimer_enqueue_reprog
  */
 static int hrtimer_switch_to_hres(void)
 {
-	struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases);
+	int cpu = smp_processor_id();
+	struct hrtimer_cpu_base *base = &per_cpu(hrtimer_bases, cpu);
 	unsigned long flags;
 
 	if (base->hres_active)
@@ -568,6 +569,8 @@ static int hrtimer_switch_to_hres(void)
 
 	if (tick_init_highres()) {
 		local_irq_restore(flags);
+		printk(KERN_WARNING "Could not switch to high resolution "
+				    "mode on CPU %d\n", cpu);
 		return 0;
 	}
 	base->hres_active = 1;
kernel/time/tick-oneshot.c +14 -1
Index: linux-2.6.22-rc4-mm/kernel/time/tick-oneshot.c
===================================================================
@@ -73,8 +73,21 @@ int tick_switch_to_oneshot(void (*handle
 	struct clock_event_device *dev = td->evtdev;
 
 	if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT) ||
-	    !tick_device_is_functional(dev))
+		    !tick_device_is_functional(dev)) {
+
+		printk(KERN_INFO "Clockevents: "
+		       "could not switch to one-shot mode:");
+		if (!dev) {
+			printk(" no tick device\n");
+		} else {
+			if (!tick_device_is_functional(dev))
+				printk(" %s is not functional.\n", dev->name);
+			else if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT))
+				printk(" %s does not support one-shot mode.\n",
+				       dev->name);
+		}
 		return -EINVAL;
+	}
 
 	td->mode = TICKDEV_MODE_ONESHOT;
 	dev->event_handler = handler;
#15 lore raw

PATCH 11/25 hrtimer: speedup hrtimer_enqueue

In reply to Thomas Gleixner

From: Ingo Molnar <[email protected]>

Speedup hrtimer_enqueue by evaluating the rbtree insertion result.

---
 kernel/hrtimer.c |   10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
kernel/hrtimer.c +6 -4
Index: linux-2.6.22-rc4-mm/kernel/hrtimer.c
===================================================================
@@ -686,6 +686,7 @@ static void enqueue_hrtimer(struct hrtim
 	struct rb_node **link = &base->active.rb_node;
 	struct rb_node *parent = NULL;
 	struct hrtimer *entry;
+	int leftmost = 1;
 
 	/*
 	 * Find the right place in the rbtree:
@@ -697,18 +698,19 @@ static void enqueue_hrtimer(struct hrtim
 		 * We dont care about collisions. Nodes with
 		 * the same expiry time stay together.
 		 */
-		if (timer->expires.tv64 < entry->expires.tv64)
+		if (timer->expires.tv64 < entry->expires.tv64) {
 			link = &(*link)->rb_left;
-		else
+		} else {
 			link = &(*link)->rb_right;
+			leftmost = 0;
+		}
 	}
 
 	/*
 	 * Insert the timer to the rbtree and check whether it
 	 * replaces the first pending timer
 	 */
-	if (!base->first || timer->expires.tv64 <
-	    rb_entry(base->first, struct hrtimer, node)->expires.tv64) {
+	if (leftmost) {
 		/*
 		 * Reprogram the clock event device. When the timer is already
 		 * expired hrtimer_enqueue_reprogram has either called the
#16 lore raw

PATCH 12/25 pcspkr: use the global PIT lock

In reply to Thomas Gleixner

Replace the pcspkr private PIT lock by the global PIT lock to serialize the PIT access all over the place.

---
 arch/x86_64/kernel/time.c   |    2 ++
 drivers/input/misc/pcspkr.c |   11 ++++++++---
 include/asm-x86_64/i8253.h  |    6 ++++++
 3 files changed, 16 insertions(+), 3 deletions(-)
arch/x86_64/kernel/time.c +2 -0
Index: linux-2.6.22-rc4-mm/arch/x86_64/kernel/time.c
===================================================================
@@ -33,6 +33,7 @@
 #include <acpi/acpi_bus.h>
 #endif
 #include <asm/8253pit.h>
+#include <asm/i8253.h>
 #include <asm/pgtable.h>
 #include <asm/vsyscall.h>
 #include <asm/timex.h>
@@ -51,6 +52,7 @@ static char *timename = NULL;
 DEFINE_SPINLOCK(rtc_lock);
 EXPORT_SYMBOL(rtc_lock);
 DEFINE_SPINLOCK(i8253_lock);
+EXPORT_SYMBOL(i8253_lock);
 
 volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
 
drivers/input/misc/pcspkr.c +8 -3
Index: linux-2.6.22-rc4-mm/drivers/input/misc/pcspkr.c
===================================================================
@@ -24,7 +24,12 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@u
 MODULE_DESCRIPTION("PC Speaker beeper driver");
 MODULE_LICENSE("GPL");
 
-static DEFINE_SPINLOCK(i8253_beep_lock);
+#ifdef CONFIG_X86
+/* Use the global PIT lock ! */
+#include <asm/i8253.h>
+#else
+static DEFINE_SPINLOCK(i8253_lock);
+#endif
 
 static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
@@ -43,7 +48,7 @@ static int pcspkr_event(struct input_dev
 	if (value > 20 && value < 32767)
 		count = PIT_TICK_RATE / value;
 
-	spin_lock_irqsave(&i8253_beep_lock, flags);
+	spin_lock_irqsave(&i8253_lock, flags);
 
 	if (count) {
 		/* enable counter 2 */
@@ -58,7 +63,7 @@ static int pcspkr_event(struct input_dev
 		outb(inb_p(0x61) & 0xFC, 0x61);
 	}
 
-	spin_unlock_irqrestore(&i8253_beep_lock, flags);
+	spin_unlock_irqrestore(&i8253_lock, flags);
 
 	return 0;
 }
include/asm-x86_64/i8253.h new file +6 -0
Index: linux-2.6.22-rc4-mm/include/asm-x86_64/i8253.h
===================================================================
@@ -0,0 +1,6 @@
+#ifndef __ASM_I8253_H__
+#define __ASM_I8253_H__
+
+extern spinlock_t i8253_lock;
+
+#endif	/* __ASM_I8253_H__ */
#17 lore raw

PATCH 13/25 i386: hpet assumes boot cpu is 0

In reply to Thomas Gleixner

From: Chris Wright <[email protected]>

I fixed this in x86_64. Looks like the kind of thing that will break voyager on i386.

---
 arch/i386/kernel/hpet.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/i386/kernel/hpet.c +1 -1
Index: linux-2.6.22-rc4-mm/arch/i386/kernel/hpet.c
===================================================================
@@ -325,7 +325,7 @@ int __init hpet_enable(void)
 		 * 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);
+		hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
 		clockevents_register_device(&hpet_clockevent);
 		global_clock_event = &hpet_clockevent;
 		return 1;
#18 lore raw

PATCH 14/25 NTP: Move the cmos update code into ntp.c

In reply to Thomas Gleixner

i386 and sparc64 have the identical code to update the cmos clock. Move it into kernel/time/ntp.c as there are other architectures coming along with the same requirements.

Cc Chris Wright <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc john stultz <[email protected]>
Cc David Miller <[email protected]>
---
 arch/i386/Kconfig          |    4 +++
 arch/i386/kernel/time.c    |   50 +-------------------------------------
 arch/sparc64/Kconfig       |    4 +++
 arch/sparc64/kernel/time.c |   53 +---------------------------------------
 include/asm-i386/timer.h   |    1 
 include/linux/time.h       |    2 +
 kernel/time/ntp.c          |   59 ++++++++++++++++++++++++++++++++++++++++++---
 7 files changed, 70 insertions(+), 103 deletions(-)
arch/i386/Kconfig +4 -0
Index: linux-2.6.22-rc4-mm/arch/i386/Kconfig
===================================================================
@@ -18,6 +18,10 @@ config GENERIC_TIME
 	bool
 	default y
 
+config GENERIC_CMOS_UPDATE
+	bool
+	default y
+
 config CLOCKSOURCE_WATCHDOG
 	bool
 	default y
arch/i386/kernel/time.c +2 -48

57 lines not on this page · raw message

arch/sparc64/kernel/time.c +2 -51

60 lines not on this page · raw message

include/linux/time.h +2 -0
Index: linux-2.6.22-rc4-mm/include/linux/time.h
===================================================================
@@ -93,6 +93,8 @@ extern struct timespec wall_to_monotonic
 extern seqlock_t xtime_lock __attribute__((weak));
 
 extern unsigned long read_persistent_clock(void);
+extern int update_persistent_clock(struct timespec now);
+extern int no_sync_cmos_clock __read_mostly;
 void timekeeping_init(void);
 
 static inline unsigned long get_seconds(void)
kernel/time/ntp.c +56 -3

80 lines not on this page · raw message

arch/sparc64/Kconfig +4 -0
Index: linux-2.6.22-rc4-mm/arch/sparc64/Kconfig
===================================================================
@@ -23,6 +23,10 @@ config GENERIC_TIME
 	bool
 	default y
 
+config GENERIC_CMOS_UPDATE
+	bool
+	default y
+
 config GENERIC_CLOCKEVENTS
 	bool
 	default y
include/asm-i386/timer.h +0 -1
Index: linux-2.6.22-rc4-mm/include/asm-i386/timer.h
===================================================================
@@ -12,7 +12,6 @@ unsigned long native_calculate_cpu_khz(v
 
 extern int timer_ack;
 extern int no_timer_check;
-extern int no_sync_cmos_clock;
 extern int recalibrate_cpu_khz(void);
 
 #ifndef CONFIG_PARAVIRT
#19 lore raw

Re: [patch-mm 14/25] NTP: Move the cmos update code into ntp.c

Hi Thomas,

Quoted 20 lines · Thomas Gleixner

i386 and sparc64 have the identical code to update the cmos clock. Move it into kernel/time/ntp.c as there are other architectures coming along with the same requirements.

Cc Chris Wright <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc john stultz <[email protected]>
Cc David Miller <[email protected]>
---
 arch/i386/Kconfig          |    4 +++
 arch/i386/kernel/time.c    |   50 +-------------------------------------
 arch/sparc64/Kconfig       |    4 +++
 arch/sparc64/kernel/time.c |   53 +---------------------------------------
 include/asm-i386/timer.h   |    1 
 include/linux/time.h       |    2 +
 kernel/time/ntp.c          |   59 ++++++++++++++++++++++++++++++++++++++++++---
 7 files changed, 70 insertions(+), 103 deletions(-)

[snip]

include/linux/time.h extern struct timespec wall_to_monotonic · line 96

Quoted 10 lines

/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
Index: linux-2.6.22-rc4-mm/include/linux/time.h
===================================================================

include/linux/time.h +1 -0
@@ -93,6 +93,8 @@ extern struct timespec wall_to_monotonic
 extern seqlock_t xtime_lock __attribute__((weak));
 
 extern unsigned long read_persistent_clock(void);
+extern int update_persistent_clock(struct timespec now);

I'm wondering if update_persistent_clock shouldn't be part of "drivers/rtc/*" framework. Do you have any idea on how this is going to be implemented on platforms that use this framework ?

Quoted 26 lines
include/linux/time.h +1 -0
+extern int no_sync_cmos_clock __read_mostly;
 void timekeeping_init(void);
 
 static inline unsigned long get_seconds(void)

Index: linux-2.6.22-rc4-mm/kernel/time/ntp.c
===================================================================

kernel/time/ntp.c +5 -1
@@ -10,6 +10,7 @@
 
 #include <linux/mm.h>
 #include <linux/time.h>
+#include <linux/timer.h>
 #include <linux/timex.h>
 #include <linux/jiffies.h>
 #include <linux/hrtimer.h>
@@ -187,12 +188,64 @@ u64 current_tick_length(void)
 	return tick_length;
 }
 
+#ifdef CONFIG_GENERIC_CMOS_UPDATE
 
-void __attribute__ ((weak)) notify_arch_cmos_timer(void)
+/* Disable the cmos update - used by virtualization and embedded */
+int no_sync_cmos_clock  __read_mostly;
+

[snip]

kernel/time/ntp.c u64 current_tick_length(void) · line 243

Quoted 6 lines
kernel/time/ntp.c +5 -0
+static void notify_cmos_timer(void)
+{
+	if (no_sync_cmos_clock)
+		mod_timer(&sync_cmos_timer, jiffies + 1);
+}

Isn't the test condition wrong ? Shouldn't it be:

	if (!no_sync_cmos_clock)
		mod_timer(&sync_cmos_timer, jiffies + 1);

Thanks,

Franck

#20 lore raw

PATCH 15/25 clocksource: add settimeofday hook for PPC

In reply to Thomas Gleixner

From: Tony Breeds <[email protected] >

I'm working on a clocksource implementation for all powerpc platforms. some of these platforms needs to do a little work as part of the settimeofday() syscall and I can't see a way to do that without adding this hook to clocksource.

From: Tony Breeds <[email protected]>

Add per clocksource hook to settimeofday().

Some clocksources need to do extra work as part of the settimeofday call, this hook make it easy to do so.

---

 include/linux/clocksource.h |    3 +++
 kernel/time/timekeeping.c   |    3 +++
 2 files changed, 6 insertions(+)
include/linux/clocksource.h +3 -0
Index: linux-2.6.22-rc4-mm/include/linux/clocksource.h
===================================================================
@@ -50,6 +50,7 @@ struct clocksource;
  * @flags:		flags describing special properties
  * @vread:		vsyscall based read
  * @resume:		resume function for the clocksource, if necessary
+ * @settimeofday:	[Optional] Do arch specific work during do_settimeofday
  * @cycle_interval:	Used internally by timekeeping core, please ignore.
  * @xtime_interval:	Used internally by timekeeping core, please ignore.
  */
@@ -68,6 +69,8 @@ struct clocksource {
 	cycle_t (*vread)(void);
 	void (*resume)(void);
 
+	void (*settimeofday)(struct clocksource *cs, struct timespec *ts);
+
 	/* timekeeping specific data, ignore */
 	cycle_t cycle_interval;
 	u64	xtime_interval;
kernel/time/timekeeping.c +3 -0
Index: linux-2.6.22-rc4-mm/kernel/time/timekeeping.c
===================================================================
@@ -159,6 +159,9 @@ int do_settimeofday(struct timespec *tv)
 	clock->error = 0;
 	ntp_clear();
 
+	if (clock->settimeofday)
+		clock->settimeofday(clock, tv);
+
 	update_vsyscall(&xtime, clock);
 
 	write_sequnlock_irqrestore(&xtime_lock, flags);
#21 lore raw

Re: [patch-mm 15/25] clocksource: add settimeofday hook for PPC

Quoted 9 lines · Thomas Gleixner

plain text document attachment
(clocksource-add-settimeofday-hook.patch)
From: Tony Breeds <[email protected] >

I'm working on a clocksource implementation for all powerpc platforms. some of these platforms needs to do a little work as part of the settimeofday() syscall and I can't see a way to do that without adding this hook to clocksource.

I'd like to see how this is used? If the code that uses this API change isn't ready yet, then this patch should really wait..

Daniel

#22 lore raw

RFC 1/1 clocksouce implementation for powerpc

Quoted 12 lines · Daniel Walker
Quoted 9 lines · Thomas Gleixner

plain text document attachment
(clocksource-add-settimeofday-hook.patch)
From: Tony Breeds <[email protected] >

I'm working on a clocksource implementation for all powerpc platforms. some of these platforms needs to do a little work as part of the settimeofday() syscall and I can't see a way to do that without adding this hook to clocksource.

Quoted 2 lines

I'd like to see how this is used? If the code that uses this API change isn't ready yet, then this patch should really wait..

This is my current patch to rework arch/powerpc/kernel/time.c to create a clocksource. It's not ready for inclusion.

powerpc needs to keep the vdso in sync whenener settimeodfay() is called. Adding the hook the to the clocksource structure was my way of allowing this to happen. There are other approaches, but this seemed to best allow for runtime. Initially I considered using update_vsyscall() but this is called from do_timer(), and I don't need this code run then :(

This has been booted on pSeries and iSeries (I'm using glibc 2.5, which uses the vdso gettimeoday())

All comments appreiated.

arch/powerpc/Kconfig +6 -0
Index: working/arch/powerpc/Kconfig
===================================================================
@@ -31,6 +31,12 @@ config MMU
 	bool
 	default y
 
+config GENERIC_TIME
+	def_bool y
+
+config GENERIC_TIME_VSYSCALL
+	def_bool y
+
 config GENERIC_HARDIRQS
 	bool
 	default y
arch/powerpc/kernel/time.c +101 -132

269 lines not on this page · raw message

Yours Tony

linux.conf.au http://linux.conf.au/ || http://lca2008.linux.org.au/
Jan 28 - Feb 02 2008 The Australian Linux Technical Conference!

#23 lore raw

Re: [RFC] clocksouce implementation for powerpc

Quoted 19 lines · Tony Breeds
Quoted 12 lines · Daniel Walker
Quoted 9 lines · Thomas Gleixner

plain text document attachment
(clocksource-add-settimeofday-hook.patch)
From: Tony Breeds <[email protected] >

I'm working on a clocksource implementation for all powerpc platforms. some of these platforms needs to do a little work as part of the settimeofday() syscall and I can't see a way to do that without adding this hook to clocksource.

Quoted 2 lines

I'd like to see how this is used? If the code that uses this API change isn't ready yet, then this patch should really wait..

This is my current patch to rework arch/powerpc/kernel/time.c to create a clocksource. It's not ready for inclusion.

Quoted 6 lines

powerpc needs to keep the vdso in sync whenener settimeodfay() is called. Adding the hook the to the clocksource structure was my way of allowing this to happen. There are other approaches, but this seemed to best allow for runtime. Initially I considered using update_vsyscall() but this is called from do_timer(), and I don't need this code run then :(

As I said in our private thread, I do think you should be using update_vsyscall() .. update_vsyscall() is just called when the time is set, usually that happens in the timer interrupt and sometimes that happens in settimeofday() ..

Quoted 4 lines

This has been booted on pSeries and iSeries (I'm using glibc 2.5, which uses the vdso gettimeoday())

All comments appreiated.

At least some of your code is duplications over what is already being worked on inside the powerpc community.. For instance, I know there is already a timebase clocksource,

http://people.redhat.com/~mingo/realtime-preempt/patch-2.6.21.5-rt17

Quoted 241 lines

Index: working/arch/powerpc/Kconfig
===================================================================

arch/powerpc/Kconfig +6 -0
@@ -31,6 +31,12 @@ config MMU
 	bool
 	default y
 
+config GENERIC_TIME
+	def_bool y
+
+config GENERIC_TIME_VSYSCALL
+	def_bool y
+
 config GENERIC_HARDIRQS
 	bool
 	default y

Index: working/arch/powerpc/kernel/time.c
===================================================================

arch/powerpc/kernel/time.c +56 -132
@@ -74,6 +74,30 @@
 #endif
 #include <asm/smp.h>
 
+/* powerpc clocksource/clockevent code */
+
+/* TODO:
+ *  o Code style
+ *    * Variable names ... be consistent.
+ *
+ * TODO: Clocksource
+ *  o Need a _USE_RTC() clocksource impelementation
+ *  o xtime:  Either time.c manages it, or clocksource does, not both
+ */
+
+#include <linux/clocksource.h>
+
+static struct clocksource clocksource_timebase = {
+	.name         = "timebase",
+	.rating       = 200,
+	.flags        = CLOCK_SOURCE_IS_CONTINUOUS,
+	.mask         = CLOCKSOURCE_MASK(64),
+	.shift        = 22,
+	.mult         = 0,	/* To be filled in */
+	.read         = NULL,   /* To be filled in */
+	.settimeofday = NULL,   /* To be filled in */
+};
+
 /* keep track of when we need to update the rtc */
 time_t last_rtc_update;
 #ifdef CONFIG_PPC_ISERIES
@@ -376,65 +400,6 @@ static __inline__ void timer_check_rtc(v
         }
 }
 
-/*
- * This version of gettimeofday has microsecond resolution.
- */
-static inline void __do_gettimeofday(struct timeval *tv)
-{
-	unsigned long sec, usec;
-	u64 tb_ticks, xsec;
-	struct gettimeofday_vars *temp_varp;
-	u64 temp_tb_to_xs, temp_stamp_xsec;
-
-	/*
-	 * These calculations are faster (gets rid of divides)
-	 * if done in units of 1/2^20 rather than microseconds.
-	 * The conversion to microseconds at the end is done
-	 * without a divide (and in fact, without a multiply)
-	 */
-	temp_varp = do_gtod.varp;
-
-	/* Sampling the time base must be done after loading
-	 * do_gtod.varp in order to avoid racing with update_gtod.
-	 */
-	data_barrier(temp_varp);
-	tb_ticks = get_tb() - temp_varp->tb_orig_stamp;
-	temp_tb_to_xs = temp_varp->tb_to_xs;
-	temp_stamp_xsec = temp_varp->stamp_xsec;
-	xsec = temp_stamp_xsec + mulhdu(tb_ticks, temp_tb_to_xs);
-	sec = xsec / XSEC_PER_SEC;
-	usec = (unsigned long)xsec & (XSEC_PER_SEC - 1);
-	usec = SCALE_XSEC(usec, 1000000);
-
-	tv->tv_sec = sec;
-	tv->tv_usec = usec;
-}
-
-void do_gettimeofday(struct timeval *tv)
-{
-	if (__USE_RTC()) {
-		/* do this the old way */
-		unsigned long flags, seq;
-		unsigned int sec, nsec, usec;
-
-		do {
-			seq = read_seqbegin_irqsave(&xtime_lock, flags);
-			sec = xtime.tv_sec;
-			nsec = xtime.tv_nsec + tb_ticks_since(tb_last_jiffy);
-		} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-		usec = nsec / 1000;
-		while (usec >= 1000000) {
-			usec -= 1000000;
-			++sec;
-		}
-		tv->tv_sec = sec;
-		tv->tv_usec = usec;
-		return;
-	}
-	__do_gettimeofday(tv);
-}
-
-EXPORT_SYMBOL(do_gettimeofday);
 
 /*
  * There are two copies of tb_to_xs and stamp_xsec so that no
@@ -666,8 +631,8 @@ void timer_interrupt(struct pt_regs * re
 		if (per_cpu(last_jiffy, cpu) >= tb_next_jiffy) {
 			tb_last_jiffy = tb_next_jiffy;
 			do_timer(1);
-			timer_recalc_offset(tb_last_jiffy);
-			timer_check_rtc();
+			/* timer_recalc_offset() && timer_check_rtc()
+			 * are now called from update_vsyscall() */
 		}
 		write_sequnlock(&xtime_lock);
 	}
@@ -739,77 +704,6 @@ unsigned long long sched_clock(void)
 	return mulhdu(get_tb() - boot_tb, tb_to_ns_scale) << tb_to_ns_shift;
 }
 
-int do_settimeofday(struct timespec *tv)
-{
-	time_t wtm_sec, new_sec = tv->tv_sec;
-	long wtm_nsec, new_nsec = tv->tv_nsec;
-	unsigned long flags;
-	u64 new_xsec;
-	unsigned long tb_delta;
-
-	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
-		return -EINVAL;
-
-	write_seqlock_irqsave(&xtime_lock, flags);
-
-	/*
-	 * Updating the RTC is not the job of this code. If the time is
-	 * stepped under NTP, the RTC will be updated after STA_UNSYNC
-	 * is cleared.  Tools like clock/hwclock either copy the RTC
-	 * to the system time, in which case there is no point in writing
-	 * to the RTC again, or write to the RTC but then they don't call
-	 * settimeofday to perform this operation.
-	 */
-#ifdef CONFIG_PPC_ISERIES
-	if (firmware_has_feature(FW_FEATURE_ISERIES) && first_settimeofday) {
-		iSeries_tb_recal();
-		first_settimeofday = 0;
-	}
-#endif
-
-	/* Make userspace gettimeofday spin until we're done. */
-	++vdso_data->tb_update_count;
-	smp_mb();
-
-	/*
-	 * Subtract off the number of nanoseconds since the
-	 * beginning of the last tick.
-	 */
-	tb_delta = tb_ticks_since(tb_last_jiffy);
-	tb_delta = mulhdu(tb_delta, do_gtod.varp->tb_to_xs); /* in xsec */
-	new_nsec -= SCALE_XSEC(tb_delta, 1000000000);
-
-	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - new_sec);
-	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - new_nsec);
-
- 	set_normalized_timespec(&xtime, new_sec, new_nsec);
-	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
-
-	/* In case of a large backwards jump in time with NTP, we want the 
-	 * clock to be updated as soon as the PLL is again in lock.
-	 */
-	last_rtc_update = new_sec - 658;
-
-	ntp_clear();
-
-	new_xsec = xtime.tv_nsec;
-	if (new_xsec != 0) {
-		new_xsec *= XSEC_PER_SEC;
-		do_div(new_xsec, NSEC_PER_SEC);
-	}
-	new_xsec += (u64)xtime.tv_sec * XSEC_PER_SEC;
-	update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs);
-
-	vdso_data->tz_minuteswest = sys_tz.tz_minuteswest;
-	vdso_data->tz_dsttime = sys_tz.tz_dsttime;
-
-	write_sequnlock_irqrestore(&xtime_lock, flags);
-	clock_was_set();
-	return 0;
-}
-
-EXPORT_SYMBOL(do_settimeofday);
-
 static int __init get_freq(char *name, int cells, unsigned long *val)
 {
 	struct device_node *cpu;
@@ -878,6 +772,78 @@ unsigned long get_boot_time(void)
 		      tm.tm_hour, tm.tm_min, tm.tm_sec);
 }
 
+/* clocksource code */
+static cycle_t timebase_read(void)
+{
+	return (cycle_t)get_tb();
+}
+
+static void clocksource_settimeofday(struct clocksource *cs,
+                                     struct timespec *ts)
+{
+	u64 new_xsec;
+
+#ifdef CONFIG_PPC_ISERIES
+	if (firmware_has_feature(FW_FEATURE_ISERIES) && first_settimeofday) {
+		iSeries_tb_recal();
+		first_settimeofday = 0;
+	}
+#endif
+
+	/* Make userspace gettimeofday spin until we're done. */
+	++vdso_data->tb_update_count;
+	smp_mb();
+
+	/* In case of a large backwards jump in time with NTP, we want the
+	 * clock to be updated as soon as the PLL is again in lock.
+	 */
+	last_rtc_update = xtime.tv_sec - 658;
+
+	new_xsec = xtime.tv_nsec;
+	if (new_xsec != 0) {
+		new_xsec *= XSEC_PER_SEC;

arch/powerpc/kernel/time.c unsigned long get_boot_time(void) · line 814

Quoted 10 lines
arch/powerpc/kernel/time.c +10 -0
+		do_div(new_xsec, NSEC_PER_SEC);
+	}
+
+	new_xsec += (u64)xtime.tv_sec * XSEC_PER_SEC;
+
+	vdso_data->tz_minuteswest = sys_tz.tz_minuteswest;
+	vdso_data->tz_dsttime = sys_tz.tz_dsttime;
+
+	update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs);
+}

It does look too large to run from interrupt context, but it also looks like it could get cleaned out more ..

arch/powerpc/kernel/time.c unsigned long get_boot_time(void) · line 820

Quoted 5 lines
arch/powerpc/kernel/time.c +5 -0
+void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
+{
+	timer_recalc_offset(tb_last_jiffy);
+	timer_check_rtc();
+}

Hmm .. This doesn't look like it's taking into account that the time has changed .. Your time has effectively incremented by one jiffie .. The vdso_data doesn't appear to be updated ..

Quoted 43 lines
arch/powerpc/kernel/time.c +28 -0
+void __init clocksource_init(void)
+{
+	int mult;
+
+	if (__USE_RTC())
+		return;
+
+	mult = clocksource_hz2mult(tb_ticks_per_sec,
+	                           clocksource_timebase.shift);
+	clocksource_timebase.mult = mult;
+
+	clocksource_timebase.read = timebase_read;
+	clocksource_timebase.settimeofday = clocksource_settimeofday;
+
+	if (clocksource_register(&clocksource_timebase)) {
+		printk(KERN_ERR "clocksource: %s is already registered\n",
+		       clocksource_timebase.name);
+		return;
+	}
+
+	printk(KERN_INFO "clocksource: %s mult[%x] shift[%d] registered\n",
+	       clocksource_timebase.name,
+	       clocksource_timebase.mult, clocksource_timebase.shift);
+}
+
 /* This function is only called on the boot processor */
 void __init time_init(void)
 {
@@ -999,6 +965,9 @@ void __init time_init(void)
 	                        -xtime.tv_sec, -xtime.tv_nsec);
 	write_sequnlock_irqrestore(&xtime_lock, flags);
 
+	/* Register the clocksource */
+	clocksource_init();
+
 	/* Not exact, but the timer interrupt takes care of this */
 	set_dec(tb_ticks_per_jiffy);
 }

Yours Tony

linux.conf.au http://linux.conf.au/ || http://lca2008.linux.org.au/
Jan 28 - Feb 02 2008 The Australian Linux Technical Conference!

#24 lore raw

Re: [RFC] clocksouce implementation for powerpc

Quoted 23 lines · Daniel Walker
Quoted 23 lines
arch/powerpc/kernel/time.c +23 -0
+static void clocksource_settimeofday(struct clocksource *cs,
+                                     struct timespec *ts)
+{
+	u64 new_xsec;
+
+#ifdef CONFIG_PPC_ISERIES
+	if (firmware_has_feature(FW_FEATURE_ISERIES) && first_settimeofday) {
+		iSeries_tb_recal();
+		first_settimeofday = 0;
+	}
+#endif
+
+	/* Make userspace gettimeofday spin until we're done. */
+	++vdso_data->tb_update_count;
+	smp_mb();
+
+	/* In case of a large backwards jump in time with NTP, we want the
+	 * clock to be updated as soon as the PLL is again in lock.
+	 */
+	last_rtc_update = xtime.tv_sec - 658;
+
+	new_xsec = xtime.tv_nsec;
+	if (new_xsec != 0) {
Quoted 8 lines

arch/powerpc/kernel/time.c unsigned long get_boot_time(void) · line 811

Quoted 8 lines
arch/powerpc/kernel/time.c +8 -0
+		new_xsec *= XSEC_PER_SEC;
+		do_div(new_xsec, NSEC_PER_SEC);
+	}
+
+	new_xsec += (u64)xtime.tv_sec * XSEC_PER_SEC;
+
+	vdso_data->tz_minuteswest = sys_tz.tz_minuteswest;
+	vdso_data->tz_dsttime = sys_tz.tz_dsttime;

I'm not sure why these are copied *only* here. Shouldn't they be copied
only once, at init. time?

Quoted 5 lines

arch/powerpc/kernel/time.c unsigned long get_boot_time(void) · line 814

Quoted 3 lines
arch/powerpc/kernel/time.c +3 -0
+
+	update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs);
+}

It does look too large to run from interrupt context,

You mean if this would have been "included" into update_vsyscall()?

Quoted 2 lines

but it also looks
like it could get cleaned out more ..

Yeah, at least new_xsec calculation is duplicated in timer_recalc_offset()..

Quoted 8 lines

arch/powerpc/kernel/time.c unsigned long get_boot_time(void) · line 820

Quoted 5 lines
arch/powerpc/kernel/time.c +5 -0
+void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
+{
+	timer_recalc_offset(tb_last_jiffy);
+	timer_check_rtc();
+}

Hmm .. This doesn't look like it's taking into account that the time has changed ..

Why? By the time it gets called (form the timer softirq context)
tb_last_jiffy should've been incremented. Well, this won't happen wither in or right after the timer interrupt... since timer has no IRQ on PowerPC -- it signals "exception". Well, HRT works somehow anyway. :-)

Quoted 2 lines

Your time has effectively incremented by one jiffie .. The vdso_data doesn't appear to be updated ..

Moreover, it will get called for settimeofday() as well which would seem
to double the overhead since your clocksource hook will get called beforehand.

WBR, Sergei

#25 lore raw

Re: [RFC] clocksouce implementation for powerpc

Quoted 10 lines · Sergei Shtylyov
Quoted 8 lines

arch/powerpc/kernel/time.c unsigned long get_boot_time(void) · line 820

Quoted 5 lines
arch/powerpc/kernel/time.c +5 -0
+void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
+{
+	timer_recalc_offset(tb_last_jiffy);
+	timer_check_rtc();
+}

Hmm .. This doesn't look like it's taking into account that the time has changed ..

Why? By the time it gets called (form the timer softirq context)

It is called from interrupt context at least in mainline. Only the -rt patch moves this to the softirq.

tglx

#26 lore raw

Re: [RFC] clocksouce implementation for powerpc

Hello.

Quoted 6 lines · Thomas Gleixner
Quoted 6 lines
Quoted 5 lines
Quoted 5 lines
arch/powerpc/kernel/time.c +5 -0
+void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
+{
+	timer_recalc_offset(tb_last_jiffy);
+	timer_check_rtc();
+}
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

Hmm .. This doesn't look like it's taking into account that the time has changed ..

Why? By the time it gets called (form the timer softirq context)

It is called from interrupt context at least in mainline. Only the -rt patch moves this to the softirq.

Anyway, by the time it gets called, tb_last_jiffy gets updated.

Quoted 1 line

tglx

WBR, Sergei

#27 lore raw

Re: [RFC] clocksouce implementation for powerpc

In reply to Daniel Walker

On Wed, Jun 20, 2007 at 07:57:19AM -0700, Daniel Walker wrote:

Hi Daniel.

Quoted 4 lines

As I said in our private thread, I do think you should be using update_vsyscall() .. update_vsyscall() is just called when the time is set, usually that happens in the timer interrupt and sometimes that happens in settimeofday() ..

Well I've taken another look at the code and I think I can probably restructure my code to use update_vsyscall(). I thought I needed a hook that was called /only/ from settimeofday() (which as you say doesn't match update_vsyscall()'s usage).

I'll try again and see what problems I hit.

Quoted 5 lines

At least some of your code is duplications over what is already being worked on inside the powerpc community.. For instance, I know there is already a timebase clocksource,

http://people.redhat.com/~mingo/realtime-preempt/patch-2.6.21.5-rt17

Thanks. The one in -rt doesn't seem to support the VDSO. however I see that there is duplication of effort there.

Quoted 3 lines

Hmm .. This doesn't look like it's taking into account that the time has changed .. Your time has effectively incremented by one jiffie .. The vdso_data doesn't appear to be updated ..

Unless I miss your meaning, the vdso is updated in timer_recalc_offset()/update_gtod() when needed.

Yours Tony

linux.conf.au http://linux.conf.au/ || http://lca2008.linux.org.au/
Jan 28 - Feb 02 2008 The Australian Linux Technical Conference!

#28 lore raw

Re: [RFC] clocksouce implementation for powerpc

In reply to Tony Breeds

Hello.

Quoted 9 lines · Tony Breeds
Quoted 8 lines
Quoted 8 lines

plain text document attachment
(clocksource-add-settimeofday-hook.patch)
From: Tony Breeds <[email protected] >

I'm working on a clocksource implementation for all powerpc platforms. some of these platforms needs to do a little work as part of the settimeofday() syscall and I can't see a way to do that without adding this hook to clocksource.

Quoted 5 lines
Quoted 2 lines

I'd like to see how this is used? If the code that uses this API change isn't ready yet, then this patch should really wait..

This is my current patch to rework arch/powerpc/kernel/time.c to create a clocksource. It's not ready for inclusion.

I guess it's been based on the prior work by John Stultz (and me too :-)?

Quoted 9 lines

powerpc needs to keep the vdso in sync whenener settimeodfay() is called. Adding the hook the to the clocksource structure was my way of allowing this to happen. There are other approaches, but this seemed to best allow for runtime. Initially I considered using update_vsyscall() but this is called from do_timer(), and I don't need this code run then :(

This has been booted on pSeries and iSeries (I'm using glibc 2.5, which uses the vdso gettimeoday())

[...]

Quoted 7 lines

Index: working/arch/powerpc/kernel/time.c
===================================================================

arch/powerpc/kernel/time.c +0 -0
@@ -74,6 +74,30 @@
 #endif
 #include <asm/smp.h>

arch/powerpc/kernel/time.c line 85

Quoted 10 lines
arch/powerpc/kernel/time.c +9 -0
 
+/* powerpc clocksource/clockevent code */
+
+/* TODO:
+ *  o Code style
+ *    * Variable names ... be consistent.
+ *
+ * TODO: Clocksource
+ *  o Need a _USE_RTC() clocksource impelementation
+ *  o xtime:  Either time.c manages it, or clocksource does, not both

If you mean the init. part, this has been already done by me -- I've
implemented read_persistent_clock() and got rid of xtime setting. What's left is to implemet update_persistent_clock() and get rid of timer_check_rtc()...

arch/powerpc/kernel/time.c line 92

Quoted 7 lines
arch/powerpc/kernel/time.c +7 -0
+ */
+
+#include <linux/clocksource.h>
+
+static struct clocksource clocksource_timebase = {
+	.name         = "timebase",
+	.rating       = 200,

Perhaps we even need to raise the rating to 300 or 400 -- according to
what <linux/clocksource.h> says?

arch/powerpc/kernel/time.c line 95

Quoted 3 lines
arch/powerpc/kernel/time.c +3 -0
+	.flags        = CLOCK_SOURCE_IS_CONTINUOUS,
+	.mask         = CLOCKSOURCE_MASK(64),
+	.shift        = 22,

PPC64 has issues with the fixed shift value, see:

http://patchwork.ozlabs.org/linuxppc/patch?id=11125

arch/powerpc/kernel/time.c line 98

Quoted 3 lines
arch/powerpc/kernel/time.c +3 -0
+	.mult         = 0,	/* To be filled in */
+	.read         = NULL,   /* To be filled in */
+	.settimeofday = NULL,   /* To be filled in */

I don't quite understand why not just init them right away? The values
are fixed anyways.

Quoted 5 lines
arch/powerpc/kernel/time.c +2 -0
+};
+
 /* keep track of when we need to update the rtc */
 time_t last_rtc_update;
 #ifdef CONFIG_PPC_ISERIES

[...]

arch/powerpc/kernel/time.c void timer_interrupt(struct pt_regs * re · line 635

Quoted 8 lines
arch/powerpc/kernel/time.c +2 -2
@@ -666,8 +631,8 @@ void timer_interrupt(struct pt_regs * re
 		if (per_cpu(last_jiffy, cpu) >= tb_next_jiffy) {
 			tb_last_jiffy = tb_next_jiffy;
 			do_timer(1);
-			timer_recalc_offset(tb_last_jiffy);
-			timer_check_rtc();
+			/* timer_recalc_offset() && timer_check_rtc()
+			 * are now called from update_vsyscall() */

I.e. in the softirq context...

[...]

WBR, Sergei

#29 lore raw

Re: [RFC] clocksouce implementation for powerpc

On Wed, Jun 20, 2007 at 08:53:47PM +0400, Sergei Shtylyov wrote:

Hi Sergei,
Thanks for taking the time to look over my patch.

Quoted 1 line

I guess it's been based on the prior work by John Stultz (and me too :-)?

At some level I guess so. John did send me a patch a while ago.

Quoted 4 lines

If you mean the init. part, this has been already done by me -- I've
implemented read_persistent_clock() and got rid of xtime setting. What's left is to implemet update_persistent_clock() and get rid of timer_check_rtc()...

Actually I think that comment is redundant. and should be removed sorry.

Quoted 2 lines

Perhaps we even need to raise the rating to 300 or 400 -- according to
what <linux/clocksource.h> says?

Sure.

Quoted 7 lines

arch/powerpc/kernel/time.c line 95

Quoted 3 lines
arch/powerpc/kernel/time.c +3 -0
+	.flags        = CLOCK_SOURCE_IS_CONTINUOUS,
+	.mask         = CLOCKSOURCE_MASK(64),
+	.shift        = 22,

PPC64 has issues with the fixed shift value, see:

http://patchwork.ozlabs.org/linuxppc/patch?id=11125

Thanks!

Quoted 6 lines

arch/powerpc/kernel/time.c line 98

Quoted 3 lines
arch/powerpc/kernel/time.c +3 -0
+	.mult         = 0,	/* To be filled in */
+	.read         = NULL,   /* To be filled in */
+	.settimeofday = NULL,   /* To be filled in */

I don't quite understand why not just init them right away? The values
are fixed anyways.

Well at least mult needs to be calculated at runtime, and I prefer to have the structure near the top of the file at which stage the read/settimeofday functions aren't defined.

Yours Tony

linux.conf.au http://linux.conf.au/ || http://lca2008.linux.org.au/
Jan 28 - Feb 02 2008 The Australian Linux Technical Conference!

#30 lore raw

Re: [RFC] clocksouce implementation for powerpc

Quoted 11 lines · Tony Breeds

Thanks for taking the time to look over my patch.

Quoted 1 line

I guess it's been based on the prior work by John Stultz (and me too :-)?

At some level I guess so. John did send me a patch a while ago.

Quoted 2 lines

If you mean the init. part, this has been already done by me -- I've
implemented read_persistent_clock() and got rid of xtime setting. What's left is to implemet update_persistent_clock() and get rid of timer_check_rtc()...

Actually I think that comment is redundant. and should be removed sorry.

I guess you haven't looked thru the -rt patch? There's much more than
John's initial patch there now, including the clockevents driver.

Quoted 8 lines
Quoted 6 lines

arch/powerpc/kernel/time.c line 98

Quoted 3 lines
arch/powerpc/kernel/time.c +3 -0
+	.mult         = 0,	/* To be filled in */
+	.read         = NULL,   /* To be filled in */
+	.settimeofday = NULL,   /* To be filled in */

I don't quite understand why not just init them right away? The values
are fixed anyways.

Well at least mult needs to be calculated at runtime, and I prefer to

I was talking about the method intializers specifically.

Quoted 2 lines

have the structure near the top of the file at which stage the read/settimeofday functions aren't defined.

I don't think it's justified anyway.

Quoted 1 line

Yours Tony

WBR, Sergei

#31 lore raw

Re: [RFC] clocksouce implementation for powerpc

In reply to Tony Breeds
Quoted 13 lines · Tony Breeds
Quoted 12 lines · Daniel Walker
Quoted 9 lines · Thomas Gleixner

plain text document attachment
(clocksource-add-settimeofday-hook.patch)
From: Tony Breeds <[email protected] >

I'm working on a clocksource implementation for all powerpc platforms. some of these platforms needs to do a little work as part of the settimeofday() syscall and I can't see a way to do that without adding this hook to clocksource.

Quoted 5 lines
Quoted 2 lines

I'd like to see how this is used? If the code that uses this API change isn't ready yet, then this patch should really wait..

This is my current patch to rework arch/powerpc/kernel/time.c to create a clocksource. It's not ready for inclusion.

Hey Tony,
Thanks for sending this out! I really appreciate this work, as its been
on my todo forever, and I've just not been able to focus on it. Currently it seems a bit minimal of a conversion (ideally there should be very little time code left), but It looks like a great start!

More comments below.

Quoted 6 lines

powerpc needs to keep the vdso in sync whenener settimeodfay() is called. Adding the hook the to the clocksource structure was my way of allowing this to happen. There are other approaches, but this seemed to best allow for runtime. Initially I considered using update_vsyscall() but this is called from do_timer(), and I don't need this code run then :(

I might be missing a subtlety in the ppc code, but I'm still not sure if I see the need for the clocksource settimeofday hook.

update_vsyscall() is intended to provide a hook that allows the generic time code to provide all the needed timekeeping state to the arch specific vsyscall implementation. It is called any time the base timekeeping variables are changed.

You're already calling timer_recalc_offset from there which looks almost as expensive as the settime hook, so I'm not sure I understand the division.

But to your credit, the patch Sergei and I have been slowly working on (I believe I've sent that to you already, but if not let me know) never got the VDSO code working, so good show!

Quoted 30 lines
arch/powerpc/kernel/time.c +30 -0
+static void clocksource_settimeofday(struct clocksource *cs,
+                                     struct timespec *ts)
+{
+	u64 new_xsec;
+
+#ifdef CONFIG_PPC_ISERIES
+	if (firmware_has_feature(FW_FEATURE_ISERIES) && first_settimeofday) {
+		iSeries_tb_recal();
+		first_settimeofday = 0;
+	}
+#endif
+
+	/* Make userspace gettimeofday spin until we're done. */
+	++vdso_data->tb_update_count;
+	smp_mb();
+
+	/* In case of a large backwards jump in time with NTP, we want the
+	 * clock to be updated as soon as the PLL is again in lock.
+	 */
+	last_rtc_update = xtime.tv_sec - 658;
+
+	new_xsec = xtime.tv_nsec;
+	if (new_xsec != 0) {
+		new_xsec *= XSEC_PER_SEC;
+		do_div(new_xsec, NSEC_PER_SEC);
+	}
+
+	new_xsec += (u64)xtime.tv_sec * XSEC_PER_SEC;
+
+	vdso_data->tz_minuteswest = sys_tz.tz_minuteswest;

arch/powerpc/kernel/time.c unsigned long get_boot_time(void) · line 820

Quoted 10 lines
arch/powerpc/kernel/time.c +10 -0
+	vdso_data->tz_dsttime = sys_tz.tz_dsttime;
+
+	update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs);
+}
+
+void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
+{
+	timer_recalc_offset(tb_last_jiffy);
+	timer_check_rtc();
+}

I think it would be enlightening to flatten this out a bit. Putting both the timer_recalc_offset and clocksource_settime code in the same function. It might illustrate where some optimizations could be done and where it might make more sense to split things up.

Also I'd leave timer_check_rtc() in the timer_interrupt for now (later moving it to tglx's generic rtc update).

thanks
-john

#32 lore raw

Re: [RFC] clocksouce implementation for powerpc

On Wed, Jun 20, 2007 at 02:06:01PM -0700, john stultz wrote:

Hi John.

Quoted 5 lines

Hey Tony,
Thanks for sending this out! I really appreciate this work, as its been
on my todo forever, and I've just not been able to focus on it. Currently it seems a bit minimal of a conversion (ideally there should be very little time code left), but It looks like a great start!

Thanks.

Quoted 7 lines

I might be missing a subtlety in the ppc code, but I'm still not sure if I see the need for the clocksource settimeofday hook.

update_vsyscall() is intended to provide a hook that allows the generic time code to provide all the needed timekeeping state to the arch specific vsyscall implementation. It is called any time the base timekeeping variables are changed.

Well as I just said the Daniel, I was under the impression I needed a hook that was only called from settimeofday(). The comments I've recieved from everyone has given me good cause to re-evaluate.

I think I can make it work without the hook, that started this discussion. Thomas, I think it's probably best to axe it now. If I /really/ need it then I'll start the discussion again :) Thanks.

Quoted 7 lines

I think it would be enlightening to flatten this out a bit. Putting both the timer_recalc_offset and clocksource_settime code in the same function. It might illustrate where some optimizations could be done and where it might make more sense to split things up.

Also I'd leave timer_check_rtc() in the timer_interrupt for now (later moving it to tglx's generic rtc update).

Yes you're rigth I don't need to move the timer_check_rtc() call.

Yours Tony

linux.conf.au http://linux.conf.au/ || http://lca2008.linux.org.au/
Jan 28 - Feb 02 2008 The Australian Linux Technical Conference!

#33 lore raw

PATCH 16/25 x86_64: untangle asm/hpet.h from asm/timex.h

In reply to Thomas Gleixner

From: Chris Wright <[email protected]>

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.

---
 drivers/char/rtc.c         |    2 +-
 include/asm-x86_64/apic.h  |    2 ++
 include/asm-x86_64/hpet.h  |    1 -
 include/asm-x86_64/timex.h |    1 -
 4 files changed, 3 insertions(+), 3 deletions(-)
drivers/char/rtc.c +1 -1
Index: linux-2.6.22-rc4-mm/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
 
include/asm-x86_64/timex.h +0 -1
Index: linux-2.6.22-rc4-mm/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>
include/asm-x86_64/apic.h +2 -0
Index: linux-2.6.22-rc4-mm/include/asm-x86_64/apic.h
===================================================================
@@ -86,6 +86,8 @@ extern void setup_apic_routing(void);
 extern void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
 				   unsigned char msg_type, unsigned char mask);
 
+extern int apic_is_clustered_box(void);
+
 #define K8_APIC_EXT_LVT_BASE    0x500
 #define K8_APIC_EXT_INT_MSG_FIX 0x0
 #define K8_APIC_EXT_INT_MSG_SMI 0x2
include/asm-x86_64/hpet.h +0 -1
Index: linux-2.6.22-rc4-mm/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);
#34 lore raw

PATCH 17/25 x86_64: Use generic cmos update

In reply to Thomas Gleixner

Use the generic cmos update function in kernel/time/ntp.c

Cc Chris Wright <[email protected]>
Cc john stultz <[email protected]>
Cc Andi Kleen <[email protected]>
---
 arch/x86_64/Kconfig       |    4 ++++
 arch/x86_64/kernel/time.c |   25 +++++++++----------------
 2 files changed, 13 insertions(+), 16 deletions(-)
arch/x86_64/kernel/time.c +9 -16
Index: linux-2.6.22-rc4-mm/arch/x86_64/kernel/time.c
===================================================================
@@ -82,8 +82,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;
 
@@ -123,6 +124,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);
@@ -142,12 +144,17 @@ static void set_rtc_mmss(unsigned long n
 	CMOS_WRITE(freq_select, RTC_FREQ_SELECT);
 
 	spin_unlock(&rtc_lock);
+
+	return retval;
 }
 
+int update_persistent_clock(struct timespec now)
+{
+	return set_rtc_mmss(now.tv_sec);
+}
 
 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
@@ -175,20 +182,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);
 }
 
arch/x86_64/Kconfig +4 -0
Index: linux-2.6.22-rc4-mm/arch/x86_64/Kconfig
===================================================================
@@ -32,6 +32,10 @@ config GENERIC_TIME_VSYSCALL
 	bool
 	default y
 
+config GENERIC_CMOS_UPDATE
+	bool
+	default y
+
 config ZONE_DMA32
 	bool
 	default y
#35 lore raw

PATCH 18/25 i386: move setup_pit_timer to the correct header file

In reply to Thomas Gleixner

setup_pit_timer is declared in asm-i386/timer.h. Move it to the pit header file, so it can be used by x86_64 as well.

---
 include/asm-i386/i8253.h |    2 ++
 include/asm-i386/timer.h |    1 -
 2 files changed, 2 insertions(+), 1 deletion(-)
include/asm-i386/i8253.h +2 -0
Index: linux-2.6.22-rc4-mm/include/asm-i386/i8253.h
===================================================================
@@ -18,4 +18,6 @@ static inline void pit_interrupt_hook(vo
 	global_clock_event->event_handler(global_clock_event);
 }
 
+extern void setup_pit_timer(void);
+
 #endif	/* __ASM_I8253_H__ */
include/asm-i386/timer.h +0 -1
Index: linux-2.6.22-rc4-mm/include/asm-i386/timer.h
===================================================================
@@ -6,7 +6,6 @@
 
 #define TICK_SIZE (tick_nsec / 1000)
 
-void setup_pit_timer(void);
 unsigned long long native_sched_clock(void);
 unsigned long native_calculate_cpu_khz(void);
 
#36 lore raw

PATCH 19/25 x86-64: remove dead code and other janitor work in tsc.c

In reply to Thomas Gleixner

Remove unused code and variables and do some codingstyle / whitespace cleanups while at it.

---
 arch/x86_64/kernel/tsc.c |   41 +++++++++++------------------------------
 1 file changed, 11 insertions(+), 30 deletions(-)
arch/x86_64/kernel/tsc.c +11 -30
Index: linux-2.6.22-rc4-mm/arch/x86_64/kernel/tsc.c
===================================================================
@@ -35,25 +35,9 @@ static inline int check_tsc_unstable(voi
  * first tick after the change will be slightly wrong.
  */
 
-#include <linux/workqueue.h>
-
-static unsigned int cpufreq_delayed_issched = 0;
-static unsigned int cpufreq_init = 0;
-static struct work_struct cpufreq_delayed_get_work;
-
-static void handle_cpufreq_delayed_get(struct work_struct *v)
-{
-	unsigned int cpu;
-	for_each_online_cpu(cpu) {
-		cpufreq_get(cpu);
-	}
-	cpufreq_delayed_issched = 0;
-}
-
-static unsigned int  ref_freq = 0;
-static unsigned long loops_per_jiffy_ref = 0;
-
-static unsigned long tsc_khz_ref = 0;
+static unsigned int  ref_freq;
+static unsigned long loops_per_jiffy_ref;
+static unsigned long tsc_khz_ref;
 
 static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
 				 void *data)
@@ -97,10 +81,8 @@ static struct notifier_block time_cpufre
 
 static int __init cpufreq_tsc(void)
 {
-	INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get);
-	if (!cpufreq_register_notifier(&time_cpufreq_notifier_block,
-				       CPUFREQ_TRANSITION_NOTIFIER))
-		cpufreq_init = 1;
+	cpufreq_register_notifier(&time_cpufreq_notifier_block,
+				  CPUFREQ_TRANSITION_NOTIFIER);
 	return 0;
 }
 
@@ -108,8 +90,6 @@ core_initcall(cpufreq_tsc);
 
 #endif
 
-static int tsc_unstable = 0;
-
 /*
  * Make an educated guess if the TSC is trustworthy and synchronized
  * over all CPUs.
@@ -122,17 +102,18 @@ __cpuinit int unsynchronized_tsc(void)
 #endif
 	/* Most intel systems have synchronized TSCs except for
 	   multi node systems */
- 	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
 #ifdef CONFIG_ACPI
 		/* But TSC doesn't tick in C3 so don't use it there */
-		if (acpi_gbl_FADT.header.length > 0 && acpi_gbl_FADT.C3latency < 1000)
+		if (acpi_gbl_FADT.header.length > 0 &&
+		    acpi_gbl_FADT.C3latency < 1000)
 			return 1;
 #endif
- 		return 0;
+		return 0;
 	}
 
- 	/* Assume multi socket systems are not synchronized */
- 	return num_present_cpus() > 1;
+	/* Assume multi socket systems are not synchronized */
+	return num_present_cpus() > 1;
 }
 
 int __init notsc_setup(char *s)
#37 lore raw

PATCH 20/25 x86_64: Convert to cleckevents

In reply to Thomas Gleixner

Convert x86_64 to the clockevents code. Share code with i386 for hpet and PIT.

Build and whitespace fixups from:
Venki Pallipadi <[email protected]>
and
Chris Wright <[email protected]>

Based on an initial patch from Chris Wright <[email protected]>

Cc Chris Wright <[email protected]>
Cc Andi Kleen <[email protected]>
---
 arch/i386/kernel/hpet.c                  |   50 ++
 arch/i386/kernel/i8253.c                 |    5 
 arch/x86_64/Kconfig                      |   12 
 arch/x86_64/kernel/Makefile              |    4 
 arch/x86_64/kernel/apic.c                |  567 +++++++++++++++++--------------
 arch/x86_64/kernel/hpet.c                |  493 --------------------------
 arch/x86_64/kernel/i8259.c               |   47 --
 arch/x86_64/kernel/mce_amd.c             |    6 
 arch/x86_64/kernel/smpboot.c             |    4 
 arch/x86_64/kernel/time.c                |  253 +------------
 arch/x86_64/kernel/tsc.c                 |   90 ++++
 drivers/acpi/processor_idle.c            |   12 
 include/asm-i386/hpet.h                  |  125 ++----
 include/asm-i386/i8253.h                 |    5 
 include/asm-i386/mach-default/io_ports.h |    5 
 include/asm-i386/tsc.h                   |    4 
 include/asm-x86_64/apic.h                |   10 
 include/asm-x86_64/hpet.h                |   77 ----
 include/asm-x86_64/i8253.h               |    8 
 include/asm-x86_64/proto.h               |    3 
 20 files changed, 569 insertions(+), 1211 deletions(-)
arch/x86_64/kernel/apic.c +320 -247
Index: linux-2.6.22-rc4-mm/arch/x86_64/kernel/apic.c
===================================================================
@@ -25,6 +25,8 @@
 #include <linux/sysdev.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
+#include <linux/clockchips.h>
+#include <linux/acpi_pmtmr.h>
 
 #include <asm/atomic.h>
 #include <asm/smp.h>
@@ -38,10 +40,10 @@
 #include <asm/timex.h>
 #include <asm/hpet.h>
 #include <asm/apic.h>
+#include <asm/i8253.h>
 
 int apic_mapped;
 int apic_verbosity;
-int apic_runs_main_timer;
 int apic_calibrate_pmtmr __initdata;
 
 int disable_apic_timer __initdata;
@@ -50,20 +52,36 @@ int disable_apic_timer __initdata;
 int local_apic_timer_c2_ok;
 EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
 
+/* Local APIC timer verification ok */
+static int local_apic_timer_verify_ok;
+
 static struct resource *ioapic_resources;
 static struct resource lapic_resource = {
 	.name = "Local APIC",
 	.flags = IORESOURCE_MEM | IORESOURCE_BUSY,
 };
 
-/*
- * cpu_mask that denotes the CPUs that needs timer interrupt coming in as
- * IPIs in place of local APIC timers
- */
-static cpumask_t timer_interrupt_broadcast_ipi_mask;
+static unsigned int calibration_result;
 
-/* Using APIC to generate smp_local_timer_interrupt? */
-int using_apic_timer __read_mostly = 0;
+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 void lapic_timer_broadcast(cpumask_t mask);
+
+static struct clock_event_device lapic_clockevent = {
+	.name		= "lapic",
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
+			| CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY,
+	.shift		= 32,
+	.set_mode	= lapic_timer_setup,
+	.set_next_event	= lapic_next_event,
+	.broadcast	= lapic_timer_broadcast,
+	.rating		= 100,
+	.irq		= -1,
+};
+static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
 
 static void apic_pm_activate(void);
 
@@ -92,8 +110,9 @@ unsigned int safe_apic_wait_icr_idle(voi
 void enable_NMI_through_LVT0 (void * dummy)
 {
 	unsigned int v;
-	
-	v = APIC_DM_NMI;                        /* unmask and set to NMI */
+
+	/* unmask and set to NMI */
+	v = APIC_DM_NMI;
 	apic_write(APIC_LVT0, v);
 }
 
@@ -120,7 +139,7 @@ void ack_bad_irq(unsigned int irq)
 	 * holds up an irq slot - in excessive cases (when multiple
 	 * unexpected vectors occur) that might lock up the APIC
 	 * completely.
-  	 * But don't ack when the APIC is disabled. -AK
+	 * But don't ack when the APIC is disabled. -AK
 	 */
 	if (!disable_apic)
 		ack_APIC_irq();
@@ -616,7 +635,7 @@ early_param("apic", apic_set_verbosity);
  * Detect and enable local APICs on non-SMP boards.
  * Original code written by Keir Fraser.
  * On AMD64 we trust the BIOS - if it says no APIC it is likely
- * not correctly set up (usually the APIC timer won't work etc.) 
+ * not correctly set up (usually the APIC timer won't work etc.)
  */
 
 static int __init detect_init_APIC (void)
@@ -759,14 +778,14 @@ 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, int irqen)
 {
 	unsigned int lvtt_value, tmp_value;
-	int cpu = smp_processor_id();
-
-	lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
 
-	if (cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask))
+	lvtt_value = LOCAL_TIMER_VECTOR;
+	if (!oneshot)
+		lvtt_value |= APIC_LVT_TIMER_PERIODIC;
+	if (!irqen)
 		lvtt_value |= APIC_LVT_MASKED;
 
 	apic_write(APIC_LVTT, lvtt_value);
@@ -779,227 +798,313 @@ 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;
+	unsigned int v;
+
+	/* Lapic used for broadcast ? */
+	if (!local_apic_timer_verify_ok)
+		return;
 
 	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. */
-	if ((pmtmr_ioport != 0) &&
-		smp_processor_id() == boot_cpu_id &&
-		apic_runs_main_timer == 1 &&
-		!cpu_isset(boot_cpu_id, timer_interrupt_broadcast_ipi_mask)) {
-		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, 1);
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		v = apic_read(APIC_LVTT);
+		v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
+		apic_write(APIC_LVTT, v);
+		break;
+	case CLOCK_EVT_MODE_RESUME:
+		/* Nothing to do here */
+		break;
 	}
+
 	local_irq_restore(flags);
 }
 
 /*
- * In this function we calibrate APIC bus clocks to the external
- * timer. Unfortunately we cannot use jiffies and the timer irq
- * to calibrate, since some later bootup code depends on getting
- * the first irq? Ugh.
- *
- * We want to do the calibration only once since we
- * want to have local timer irqs syncron. CPUs connected
- * by the same APIC bus have the very same bus frequency.
- * And we want to have irqs off anyways, no accidental
- * APIC irq that way.
+ * Local APIC timer broadcast function
  */
-
-#define TICK_COUNT 100000000
-
-static int __init calibrate_APIC_clock(void)
+static void lapic_timer_broadcast(cpumask_t mask)
 {
-	unsigned apic, apic_start;
-	unsigned long tsc, tsc_start;
-	int result;
-	/*
-	 * 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(4000000000);
-
-	apic_start = apic_read(APIC_TMCCT);
-#ifdef CONFIG_X86_PM_TIMER
-	if (apic_calibrate_pmtmr && pmtmr_ioport) {
-		pmtimer_wait(5000);  /* 5ms wait */
-		apic = apic_read(APIC_TMCCT);
-		result = (apic_start - apic) * 1000L / 5;
-	} else
+#ifdef CONFIG_SMP
+	send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
 #endif
-	{
-		rdtscll(tsc_start);
+}
 
-		do {
-			apic = apic_read(APIC_TMCCT);
-			rdtscll(tsc);
-		} while ((tsc - tsc_start) < TICK_COUNT &&
-				(apic_start - apic) < TICK_COUNT);
+static void __devinit setup_APIC_timer(void)
+{
+	struct clock_event_device *levt = &__get_cpu_var(lapic_events);
 
-		result = (apic_start - apic) * 1000L * tsc_khz /
-					(tsc - tsc_start);
-	}
-	printk("result %d\n", result);
+	memcpy(levt, &lapic_clockevent, sizeof(*levt));
+	levt->cpumask = cpumask_of_cpu(smp_processor_id());
+
+	clockevents_register_device(levt);
+}
+
+/*
+ * In this functions we calibrate APIC bus clocks to the external timer.
+ *
+ * We want to do the calibration only once since we want to have local timer
+ * irqs syncron. CPUs connected by the same APIC bus have the very same bus
+ * frequency.
+ *
+ * This was previously done by reading the PIT/HPET and waiting for a wrap
+ * around to find out, that a tick has elapsed. I have a box, where the PIT
+ * readout is broken, so it never gets out of the wait loop again. This was
+ * also reported by others.
+ *
+ * Monitoring the jiffies value is inaccurate and the clockevents
+ * infrastructure allows us to do a simple substitution of the interrupt
+ * handler.
+ *
+ * The calibration routine also uses the pm_timer when possible, as the PIT
+ * happens to run way too slow (factor 2.3 on my VAIO CoreDuo, which goes
+ * back to normal later in the boot process).
+ */
 
+#define LAPIC_CAL_LOOPS		(HZ/10)
 
-	printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n",
-		result / 1000 / 1000, result / 1000 % 1000);
+static __initdata volatile int lapic_cal_loops = -1;
+static __initdata long lapic_cal_t1, lapic_cal_t2;
+static __initdata unsigned long long lapic_cal_tsc1, lapic_cal_tsc2;
+static __initdata unsigned long lapic_cal_pm1, lapic_cal_pm2;
+static __initdata unsigned long lapic_cal_j1, lapic_cal_j2;
 
-	return result * APIC_DIVISOR / HZ;
+/*
+ * Temporary interrupt handler.
+ */
+static void __init lapic_cal_handler(struct clock_event_device *dev)
+{
+	unsigned long long tsc = 0;
+	long tapic = apic_read(APIC_TMCCT);
+	unsigned long pm = acpi_pm_read_early();
+
+	if (cpu_has_tsc)
+		rdtscll(tsc);
+
+	switch (lapic_cal_loops++) {
+	case 0:
+		lapic_cal_t1 = tapic;
+		lapic_cal_tsc1 = tsc;
+		lapic_cal_pm1 = pm;
+		lapic_cal_j1 = jiffies;
+		break;
+
+	case LAPIC_CAL_LOOPS:
+		lapic_cal_t2 = tapic;
+		lapic_cal_tsc2 = tsc;
+		if (pm < lapic_cal_pm1)
+			pm += ACPI_PM_OVRRUN;
+		lapic_cal_pm2 = pm;
+		lapic_cal_j2 = jiffies;
+		break;
+	}
 }
 
-static unsigned int calibration_result;
-
 void __init setup_boot_APIC_clock (void)
 {
-	if (disable_apic_timer) { 
-		printk(KERN_INFO "Disabling APIC timer\n"); 
-		return; 
-	} 
+	struct clock_event_device *levt = &__get_cpu_var(lapic_events);
+	const long pm_100ms = PMTMR_TICKS_PER_SEC/10;
+	const long pm_thresh = pm_100ms/100;
+	void (*real_handler)(struct clock_event_device *dev);
+	unsigned long deltaj;
+	long delta, deltapm;
+	int pm_referenced = 0;
+
+	/*
+	 * The local apic timer can be disabled via the kernel
+	 * commandline or from the test above. Register the lapic
+	 * timer as a dummy clock event source on SMP systems, so the
+	 * broadcast mechanism is used. On UP systems simply ignore it.
+	 */
+	if (disable_apic_timer) {
+		printk(KERN_INFO "Disabling APIC timer\n");
+		/* No broadcast on UP ! */
+		if (num_possible_cpus() > 1)
+			setup_APIC_timer();
+		return;
+	}
 
 	printk(KERN_INFO "Using local APIC timer interrupts.\n");
-	using_apic_timer = 1;
 
-	local_irq_disable();
+	/* Replace the global interrupt handler */
+	real_handler = global_clock_event->event_handler;
+	global_clock_event->event_handler = lapic_cal_handler;
 
-	calibration_result = calibrate_APIC_clock();
 	/*
-	 * Now set up the timer for real.
+	 * Setup the APIC counter to 1e9. There is no way the lapic
+	 * can underflow in the 100ms detection time frame
 	 */
-	setup_APIC_timer(calibration_result);
+	__setup_APIC_LVTT(1000000000, 0, 0);
 
+	/* Let the interrupts run */
 	local_irq_enable();
-}
 
-void __cpuinit setup_secondary_APIC_clock(void)
-{
-	local_irq_disable(); /* FIXME: Do we need this? --RR */
-	setup_APIC_timer(calibration_result);
-	local_irq_enable();
-}
+	while (lapic_cal_loops <= LAPIC_CAL_LOOPS)
+		cpu_relax();
 
-void disable_APIC_timer(void)
-{
-	if (using_apic_timer) {
-		unsigned long v;
+	local_irq_disable();
 
-		v = apic_read(APIC_LVTT);
-		/*
-		 * When an illegal vector value (0-15) is written to an LVT
-		 * entry and delivery mode is Fixed, the APIC may signal an
-		 * illegal vector error, with out regard to whether the mask
-		 * bit is set or whether an interrupt is actually seen on input.
-		 *
-		 * Boot sequence might call this function when the LVTT has
-		 * '0' vector value. So make sure vector field is set to
-		 * valid value.
-		 */
-		v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
-		apic_write(APIC_LVTT, v);
+	/* Restore the real event handler */
+	global_clock_event->event_handler = real_handler;
+
+	/* Build delta t1-t2 as apic timer counts down */
+	delta = lapic_cal_t1 - lapic_cal_t2;
+	apic_printk(APIC_VERBOSE, "... lapic delta = %ld\n", delta);
+
+	/* Check, if the PM timer is available */
+	deltapm = lapic_cal_pm2 - lapic_cal_pm1;
+	apic_printk(APIC_VERBOSE, "... PM timer delta = %ld\n", deltapm);
+
+	if (deltapm) {
+		unsigned long mult;
+		u64 res;
+
+		mult = clocksource_hz2mult(PMTMR_TICKS_PER_SEC, 22);
+
+		if (deltapm > (pm_100ms - pm_thresh) &&
+		    deltapm < (pm_100ms + pm_thresh)) {
+			apic_printk(APIC_VERBOSE, "... PM timer result ok\n");
+		} else {
+			res = (((u64) deltapm) *  mult) >> 22;
+			do_div(res, 1000000);
+			printk(KERN_WARNING "APIC calibration not consistent "
+			       "with PM Timer: %ldms instead of 100ms\n",
+			       (long)res);
+			/* Correct the lapic counter value */
+			res = (((u64) delta ) * pm_100ms);
+			do_div(res, deltapm);
+			printk(KERN_INFO "APIC delta adjusted to PM-Timer: "
+			       "%lu (%ld)\n", (unsigned long) res, delta);
+			delta = (long) res;
+		}
+		pm_referenced = 1;
 	}
-}
 
-void enable_APIC_timer(void)
-{
-	int cpu = smp_processor_id();
+	/* Calculate the scaled math multiplication factor */
+	lapic_clockevent.mult = div_sc(delta, TICK_NSEC * LAPIC_CAL_LOOPS, 32);
+	lapic_clockevent.max_delta_ns =
+		clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
+	lapic_clockevent.min_delta_ns =
+		clockevent_delta2ns(0xF, &lapic_clockevent);
 
-	if (using_apic_timer &&
-	    !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
-		unsigned long v;
+	calibration_result = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS;
 
-		v = apic_read(APIC_LVTT);
-		apic_write(APIC_LVTT, v & ~APIC_LVT_MASKED);
+	apic_printk(APIC_VERBOSE, "..... delta %ld\n", delta);
+	apic_printk(APIC_VERBOSE, "..... mult: %ld\n", lapic_clockevent.mult);
+	apic_printk(APIC_VERBOSE, "..... calibration result: %u\n",
+		    calibration_result);
+
+	if (cpu_has_tsc) {
+		delta = (long)(lapic_cal_tsc2 - lapic_cal_tsc1);
+		apic_printk(APIC_VERBOSE, "..... CPU clock speed is "
+			    "%ld.%04ld MHz.\n",
+			    (delta / LAPIC_CAL_LOOPS) / (1000000 / HZ),
+			    (delta / LAPIC_CAL_LOOPS) % (1000000 / HZ));
 	}
-}
 
-void switch_APIC_timer_to_ipi(void *cpumask)
-{
-	cpumask_t mask = *(cpumask_t *)cpumask;
-	int cpu = smp_processor_id();
+	apic_printk(APIC_VERBOSE, "..... host bus clock speed is "
+		    "%u.%04u MHz.\n",
+		    calibration_result / (1000000 / HZ),
+		    calibration_result % (1000000 / HZ));
 
-	if (cpu_isset(cpu, mask) &&
-	    !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
-		disable_APIC_timer();
-		cpu_set(cpu, timer_interrupt_broadcast_ipi_mask);
-	}
-}
-EXPORT_SYMBOL(switch_APIC_timer_to_ipi);
+	local_apic_timer_verify_ok = 1;
 
-void smp_send_timer_broadcast_ipi(void)
-{
-	int cpu = smp_processor_id();
-	cpumask_t mask;
+	/* We trust the pm timer based calibration */
+	if (!pm_referenced) {
+		apic_printk(APIC_VERBOSE, "... verify APIC timer\n");
 
-	cpus_and(mask, cpu_online_map, timer_interrupt_broadcast_ipi_mask);
+		/*
+		 * Setup the apic timer manually
+		 */
+		levt->event_handler = lapic_cal_handler;
+		lapic_timer_setup(CLOCK_EVT_MODE_PERIODIC, levt);
+		lapic_cal_loops = -1;
 
-	if (cpu_isset(cpu, mask)) {
-		cpu_clear(cpu, mask);
-		add_pda(apic_timer_irqs, 1);
-		smp_local_timer_interrupt();
-	}
+		/* Let the interrupts run */
+		local_irq_enable();
+
+		while(lapic_cal_loops <= LAPIC_CAL_LOOPS)
+			cpu_relax();
+
+		local_irq_disable();
+
+		/* Stop the lapic timer */
+		lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, levt);
+
+		local_irq_enable();
 
-	if (!cpus_empty(mask)) {
-		send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
+		/* Jiffies delta */
+		deltaj = lapic_cal_j2 - lapic_cal_j1;
+		apic_printk(APIC_VERBOSE, "... jiffies delta = %lu\n", deltaj);
+
+		/* Check, if the jiffies result is consistent */
+		if (deltaj >= LAPIC_CAL_LOOPS-2 && deltaj <= LAPIC_CAL_LOOPS+2)
+			apic_printk(APIC_VERBOSE, "... jiffies result ok\n");
+		else
+			local_apic_timer_verify_ok = 0;
+	} else
+		local_irq_enable();
+
+	if (!local_apic_timer_verify_ok) {
+		printk(KERN_WARNING
+		       "APIC timer disabled due to verification failure.\n");
+		/* No broadcast on UP ! */
+		if (num_possible_cpus() == 1)
+			return;
+	} else {
+		/*
+		 * If nmi_watchdog is set to IO_APIC, we need the
+		 * PIT/HPET going.  Otherwise register lapic as a dummy
+		 * device.
+		 */
+		if (nmi_watchdog != NMI_IO_APIC)
+			lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
 	}
+
+	/* Setup the lapic or request the broadcast */
+	setup_APIC_timer();
 }
 
-void switch_ipi_to_APIC_timer(void *cpumask)
+void __cpuinit setup_secondary_APIC_clock(void)
 {
-	cpumask_t mask = *(cpumask_t *)cpumask;
-	int cpu = smp_processor_id();
-
-	if (cpu_isset(cpu, mask) &&
-	    cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
-		cpu_clear(cpu, timer_interrupt_broadcast_ipi_mask);
-		enable_APIC_timer();
-	}
+	setup_APIC_timer();
 }
-EXPORT_SYMBOL(switch_ipi_to_APIC_timer);
 
 int setup_profiling_timer(unsigned int multiplier)
 {
 	return -EINVAL;
 }
 
-void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
-			    unsigned char msg_type, unsigned char mask)
+void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
+			     unsigned char msg_type, unsigned char mask)
 {
 	unsigned long reg = (lvt_off << 4) + K8_APIC_EXT_LVT_BASE;
 	unsigned int  v   = (mask << 16) | (msg_type << 8) | vector;
+
 	apic_write(reg, v);
 }
 
-#undef APIC_DIVISOR
-
 /*
  * Local timer interrupt handler. It does both profiling and
  * process statistics/rescheduling.
@@ -1010,24 +1115,36 @@ void setup_APIC_extened_lvt(unsigned cha
  * value into /proc/profile.
  */
 
-void smp_local_timer_interrupt(void)
+void local_apic_timer_interrupt(void)
 {
-	profile_tick(CPU_PROFILING);
-#ifdef CONFIG_SMP
-	update_process_times(user_mode(get_irq_regs()));
-#endif
-	if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id)
-		main_timer_handler();
+	int cpu = smp_processor_id();
+	struct clock_event_device *evt = &per_cpu(lapic_events, cpu);
+
 	/*
-	 * We take the 'long' return path, and there every subsystem
-	 * grabs the appropriate locks (kernel lock/ irq lock).
-	 *
-	 * We might want to decouple profiling from the 'long path',
-	 * and do the profiling totally in assembly.
+	 * Normally we should not be here till LAPIC has been initialized but
+	 * in some cases like kdump, its possible that there is a pending LAPIC
+	 * timer interrupt from previous kernel's context and is delivered in
+	 * new kernel the moment interrupts are enabled.
 	 *
-	 * Currently this isn't too much of an issue (performance wise),
-	 * we can take more than 100K local irqs per second on a 100 MHz P5.
+	 * Interrupts are enabled early and LAPIC is setup much later, hence
+	 * its possible that when we get here evt->event_handler is NULL.
+	 * Check for event_handler being NULL and discard the interrupt as
+	 * spurious.
+	 */
+	if (!evt->event_handler) {
+		printk(KERN_WARNING
+		       "Spurious LAPIC timer interrupt on cpu %d\n", cpu);
+		/* Switch it off */
+		lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt);
+		return;
+	}
+
+	/*
+	 * the NMI deadlock-detector uses this.
 	 */
+	add_pda(apic_timer_irqs, 1);
+
+	evt->event_handler(evt);
 }
 
 /*
@@ -1043,11 +1160,6 @@ void smp_apic_timer_interrupt(struct pt_
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
 	/*
-	 * the NMI deadlock-detector uses this.
-	 */
-	add_pda(apic_timer_irqs, 1);
-
-	/*
 	 * NOTE! We'd better ACK the irq immediately,
 	 * because timer handling can be slow.
 	 */
@@ -1059,7 +1171,7 @@ void smp_apic_timer_interrupt(struct pt_
 	 */
 	exit_idle();
 	irq_enter();
-	smp_local_timer_interrupt();
+	local_apic_timer_interrupt();
 	irq_exit();
 	set_irq_regs(old_regs);
 }
@@ -1127,21 +1239,6 @@ asmlinkage void smp_spurious_interrupt(v
 	v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1));
 	if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
 		ack_APIC_irq();
-
-#if 0
-	static unsigned long last_warning; 
-	static unsigned long skipped; 
-
-	/* see sw-dev-man vol 3, chapter 7.4.13.5 */
-	if (time_before(last_warning+30*HZ,jiffies)) { 
-		printk(KERN_INFO "spurious APIC interrupt on CPU#%d, %ld skipped.\n",
-		       smp_processor_id(), skipped);
-		last_warning = jiffies; 
-		skipped = 0;
-	} else { 
-		skipped++; 
-	} 
-#endif 
 	irq_exit();
 }
 
@@ -1173,11 +1270,11 @@ asmlinkage void smp_error_interrupt(void
 	   7: Illegal register address
 	*/
 	printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n",
-	        smp_processor_id(), v , v1);
+		smp_processor_id(), v , v1);
 	irq_exit();
 }
 
-int disable_apic; 
+int disable_apic;
 
 /*
  * This initializes the IO-APIC and APIC hardware if this is
@@ -1185,11 +1282,11 @@ int disable_apic; 
  */
 int __init APIC_init_uniprocessor (void)
 {
-	if (disable_apic) { 
+	if (disable_apic) {
 		printk(KERN_INFO "Apic disabled\n");
-		return -1; 
+		return -1;
 	}
-	if (!cpu_has_apic) { 
+	if (!cpu_has_apic) {
 		disable_apic = 1;
 		printk(KERN_INFO "Apic disabled by BIOS\n");
 		return -1;
@@ -1211,8 +1308,8 @@ int __init APIC_init_uniprocessor (void)
 	return 0;
 }
 
-static __init int setup_disableapic(char *str) 
-{ 
+static __init int setup_disableapic(char *str)
+{
 	disable_apic = 1;
 	clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
 	return 0;
@@ -1220,10 +1317,10 @@ static __init int setup_disableapic(char
 early_param("disableapic", setup_disableapic);
 
 /* same as disableapic, for compatibility */
-static __init int setup_nolapic(char *str) 
-{ 
+static __init int setup_nolapic(char *str)
+{
 	return setup_disableapic(str);
-} 
+}
 early_param("nolapic", setup_nolapic);
 
 static int __init parse_lapic_timer_c2_ok(char *arg)
@@ -1233,36 +1330,12 @@ static int __init parse_lapic_timer_c2_o
 }
 early_param("lapic_timer_c2_ok", parse_lapic_timer_c2_ok);
 
-static __init int setup_noapictimer(char *str) 
-{ 
+static __init int setup_noapictimer(char *str)
+{
 	if (str[0] != ' ' && str[0] != 0)
 		return 0;
 	disable_apic_timer = 1;
 	return 1;
-} 
-
-static __init int setup_apicmaintimer(char *str)
-{
-	apic_runs_main_timer = 1;
-	nohpet = 1;
-	return 1;
 }
-__setup("apicmaintimer", setup_apicmaintimer);
-
-static __init int setup_noapicmaintimer(char *str)
-{
-	apic_runs_main_timer = -1;
-	return 1;
-}
-__setup("noapicmaintimer", setup_noapicmaintimer);
-
-static __init int setup_apicpmtimer(char *s)
-{
-	apic_calibrate_pmtmr = 1;
-	notsc_setup(NULL);
-	return setup_apicmaintimer(NULL);
-}
-__setup("apicpmtimer", setup_apicpmtimer);
-
-__setup("noapictimer", setup_noapictimer); 
+__setup("noapictimer", setup_noapictimer);
 
arch/x86_64/kernel/time.c +29 -224

334 lines not on this page · raw message

arch/x86_64/kernel/hpet.c deleted +0 -493

493 lines not on this page · raw message

arch/x86_64/Kconfig +12 -0
Index: linux-2.6.22-rc4-mm/arch/x86_64/Kconfig
===================================================================
@@ -28,6 +28,18 @@ config GENERIC_TIME
 	bool
 	default y
 
+config GENERIC_CLOCKEVENTS
+	bool
+	default y
+
+config GENERIC_CLOCKEVENTS_BROADCAST
+	bool
+	default y
+
+config NONIRQ_WAKEUP
+	bool
+	default y
+
 config GENERIC_TIME_VSYSCALL
 	bool
 	default y
include/asm-x86_64/hpet.h +1 -76

78 lines not on this page · raw message

include/asm-i386/hpet.h +50 -75

162 lines not on this page · raw message

arch/i386/kernel/hpet.c +45 -5

97 lines not on this page · raw message

arch/x86_64/kernel/mce_amd.c +3 -3
Index: linux-2.6.22-rc4-mm/arch/x86_64/kernel/mce_amd.c
===================================================================
@@ -157,9 +157,9 @@ void __cpuinit mce_amd_feature_init(stru
 			high |= K8_APIC_EXT_LVT_ENTRY_THRESHOLD << 20;
 			wrmsr(address, low, high);
 
-			setup_APIC_extened_lvt(K8_APIC_EXT_LVT_ENTRY_THRESHOLD,
-					       THRESHOLD_APIC_VECTOR,
-					       K8_APIC_EXT_INT_MSG_FIX, 0);
+			setup_APIC_extended_lvt(K8_APIC_EXT_LVT_ENTRY_THRESHOLD,
+						THRESHOLD_APIC_VECTOR,
+						K8_APIC_EXT_INT_MSG_FIX, 0);
 
 			threshold_defaults.address = address;
 			threshold_restart_bank(&threshold_defaults, 0, 0);
arch/x86_64/kernel/smpboot.c +0 -4
Index: linux-2.6.22-rc4-mm/arch/x86_64/kernel/smpboot.c
===================================================================
@@ -223,8 +223,6 @@ void __cpuinit smp_callin(void)
 	local_irq_disable();
 	Dprintk("Stack at about %p\n",&cpuid);
 
-	disable_APIC_timer();
-
 	/*
 	 * Save our processor parameters
 	 */
@@ -348,8 +346,6 @@ void __cpuinit start_secondary(void)
 		enable_8259A_irq(0);
 	}
 
-	enable_APIC_timer();
-
 	/*
 	 * The sibling maps must be set before turing the online map on for
 	 * this cpu
drivers/acpi/processor_idle.c +0 -12
Index: linux-2.6.22-rc4-mm/drivers/acpi/processor_idle.c
===================================================================
@@ -203,21 +203,12 @@ static void acpi_timer_check_state(int s
 
 static void acpi_propagate_timer_broadcast(struct acpi_processor *pr)
 {
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
 	unsigned long reason;
 
 	reason = pr->power.timer_broadcast_on_state < INT_MAX ?
 		CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
 
 	clockevents_notify(reason, &pr->id);
-#else
-	cpumask_t mask = cpumask_of_cpu(pr->id);
-
-	if (pr->power.timer_broadcast_on_state < INT_MAX)
-		on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1);
-	else
-		on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1);
-#endif
 }
 
 /* Power(C) State timer broadcast control */
@@ -225,8 +216,6 @@ static void acpi_state_timer_broadcast(s
 				       struct acpi_processor_cx *cx,
 				       int broadcast)
 {
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
-
 	int state = cx - pr->power.states;
 
 	if (state >= pr->power.timer_broadcast_on_state) {
@@ -236,7 +225,6 @@ static void acpi_state_timer_broadcast(s
 			CLOCK_EVT_NOTIFY_BROADCAST_EXIT;
 		clockevents_notify(reason, &pr->id);
 	}
-#endif
 }
 
 #else
include/asm-x86_64/i8253.h +2 -6
Index: linux-2.6.22-rc4-mm/include/asm-x86_64/i8253.h
===================================================================
@@ -1,6 +1,2 @@
-#ifndef __ASM_I8253_H__
-#define __ASM_I8253_H__
-
-extern spinlock_t i8253_lock;
-
-#endif	/* __ASM_I8253_H__ */
+#include <asm-i386/i8253.h>
+#include <asm/8253pit.h>
include/asm-x86_64/proto.h +0 -3
Index: linux-2.6.22-rc4-mm/include/asm-x86_64/proto.h
===================================================================
@@ -51,9 +51,6 @@ extern void reserve_bootmem_generic(unsi
 
 extern void load_gs_index(unsigned gs);
 
-extern void stop_timer_interrupt(void);
-extern void main_timer_handler(void);
-
 extern unsigned long end_pfn_map; 
 
 extern void show_trace(struct task_struct *, struct pt_regs *, unsigned long * rsp);
include/asm-x86_64/apic.h +2 -8
Index: linux-2.6.22-rc4-mm/include/asm-x86_64/apic.h
===================================================================
@@ -79,12 +79,10 @@ extern void smp_local_timer_interrupt (v
 extern void setup_boot_APIC_clock (void);
 extern void setup_secondary_APIC_clock (void);
 extern int APIC_init_uniprocessor (void);
-extern void disable_APIC_timer(void);
-extern void enable_APIC_timer(void);
 extern void setup_apic_routing(void);
 
-extern void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
-				   unsigned char msg_type, unsigned char mask);
+extern void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
+				    unsigned char msg_type, unsigned char mask);
 
 extern int apic_is_clustered_box(void);
 
@@ -95,10 +93,6 @@ extern int apic_is_clustered_box(void);
 #define K8_APIC_EXT_INT_MSG_EXT 0x7
 #define K8_APIC_EXT_LVT_ENTRY_THRESHOLD    0
 
-void smp_send_timer_broadcast_ipi(void);
-void switch_APIC_timer_to_ipi(void *cpumask);
-void switch_ipi_to_APIC_timer(void *cpumask);
-
 #define ARCH_APICTIMER_STOPS_ON_C3	1
 
 extern unsigned boot_cpu_id;
arch/i386/kernel/i8253.c +3 -2
Index: linux-2.6.22-rc4-mm/arch/i386/kernel/i8253.c
===================================================================
@@ -15,8 +15,6 @@
 #include <asm/io.h>
 #include <asm/timer.h>
 
-#include "io_ports.h"
-
 DEFINE_SPINLOCK(i8253_lock);
 EXPORT_SYMBOL(i8253_lock);
 
@@ -122,6 +120,7 @@ void __init setup_pit_timer(void)
 	global_clock_event = &pit_clockevent;
 }
 
+#ifndef CONFIG_X86_64
 /*
  * Since the PIT overflows every tick, its not very useful
  * to just read by itself. So use jiffies to emulate a free
@@ -206,3 +205,5 @@ static int __init init_pit_clocksource(v
 	return clocksource_register(&clocksource_pit);
 }
 arch_initcall(init_pit_clocksource);
+
+#endif
arch/x86_64/kernel/tsc.c +90 -0

103 lines not on this page · raw message

include/asm-i386/tsc.h +4 -0
Index: linux-2.6.22-rc4-mm/include/asm-i386/tsc.h
===================================================================
@@ -71,4 +71,8 @@ extern void init_tsc_clocksource(void);
 extern void check_tsc_sync_source(int cpu);
 extern void check_tsc_sync_target(void);
 
+#ifdef CONFIG_X86_64
+extern void tsc_calibrate(void);
+#endif
+
 #endif
arch/x86_64/kernel/i8259.c +0 -47

59 lines not on this page · raw message

include/asm-i386/mach-default/io_ports.h +0 -5
Index: linux-2.6.22-rc4-mm/include/asm-i386/mach-default/io_ports.h
===================================================================
@@ -7,11 +7,6 @@
 #ifndef _MACH_IO_PORTS_H
 #define _MACH_IO_PORTS_H
 
-/* i8253A PIT registers */
-#define PIT_MODE		0x43
-#define PIT_CH0			0x40
-#define PIT_CH2			0x42
-
 /* i8259A PIC registers */
 #define PIC_MASTER_CMD		0x20
 #define PIC_MASTER_IMR		0x21
include/asm-i386/i8253.h +5 -0
Index: linux-2.6.22-rc4-mm/include/asm-i386/i8253.h
===================================================================
@@ -3,6 +3,11 @@
 
 #include <linux/clockchips.h>
 
+/* i8253A PIT registers */
+#define PIT_MODE		0x43
+#define PIT_CH0			0x40
+#define PIT_CH2			0x42
+
 extern spinlock_t i8253_lock;
 
 extern struct clock_event_device *global_clock_event;
arch/x86_64/kernel/Makefile +3 -1
Index: linux-2.6.22-rc4-mm/arch/x86_64/kernel/Makefile
===================================================================
@@ -9,7 +9,7 @@ obj-y	:= process.o signal.o entry.o trap
 		x8664_ksyms.o i387.o syscall.o vsyscall.o \
 		setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o \
 		pci-dma.o pci-nommu.o alternative.o hpet.o tsc.o bugs.o \
-		perfctr-watchdog.o sched-clock.o
+		perfctr-watchdog.o sched-clock.o i8253.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-$(CONFIG_X86_MCE)		+= mce.o therm_throt.o
@@ -49,6 +49,8 @@ obj-y				+= pcspeaker.o
 
 CFLAGS_vsyscall.o		:= $(PROFILING) -g0
 
+i8253-y				+= ../../i386/kernel/i8253.o
+hpet-y				+= ../../i386/kernel/hpet.o
 therm_throt-y                   += ../../i386/kernel/cpu/mcheck/therm_throt.o
 bootflag-y			+= ../../i386/kernel/bootflag.o
 legacy_serial-y			+= ../../i386/kernel/legacy_serial.o
#38 lore raw

PATCH 21/25 x86_64: hpet restore vread

In reply to Thomas Gleixner
Quoted 1 line

From [email protected]

It seems the hpet clocksource's vread method was lost in the x86_64 conversion to clockevents. So here it is.

 arch/i386/kernel/hpet.c |   10 ++++++++++
 1 file changed, 10 insertions(+)
arch/i386/kernel/hpet.c +10 -0
Index: linux-2.6.22-rc4-mm/arch/i386/kernel/hpet.c
===================================================================
@@ -255,6 +255,13 @@ static cycle_t read_hpet(void)
 	return (cycle_t)hpet_readl(HPET_COUNTER);
 }
 
+#ifdef CONFIG_X86_64
+static cycle_t __vsyscall_fn vread_hpet(void)
+{
+	return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0);
+}
+#endif
+
 static struct clocksource clocksource_hpet = {
 	.name		= "hpet",
 	.rating		= 250,
@@ -263,6 +270,9 @@ static struct clocksource clocksource_hp
 	.shift		= HPET_SHIFT,
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 	.resume		= hpet_start_counter,
+#ifdef CONFIG_X86_64
+	.vread		= vread_hpet,
+#endif
 };
 
 /*
#39 lore raw

PATCH 22/25 x86_64: restore restore nohpet cmdline

In reply to Thomas Gleixner

From: Chris Wright <[email protected]>

Lost when merged with i386. Happy to drop, but I suspect Andi would rather not break existing users (I noticed because it was part of my testing). If dropped, Documentation needs updating.

---
 arch/i386/kernel/hpet.c |    7 +++++++
 1 file changed, 7 insertions(+)
arch/i386/kernel/hpet.c +7 -0
Index: linux-2.6.22-rc4-mm/arch/i386/kernel/hpet.c
===================================================================
@@ -89,6 +89,13 @@ static int __init hpet_setup(char* str)
 }
 __setup("hpet=", hpet_setup);
 
+static int __init disable_hpet(char *str)
+{
+	boot_hpet_disable = 1;
+	return 1;
+}
+__setup("nohpet", disable_hpet);
+
 static inline int is_hpet_capable(void)
 {
 	return (!boot_hpet_disable && hpet_address);
#40 lore raw

PATCH 23/25 x86-64 block irq balancing for timer

In reply to Thomas Gleixner

From: Venki Pallipadi <[email protected]>

Disable irq balancing on IRQ0.

---
 arch/x86_64/kernel/time.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86_64/kernel/time.c +1 -1
Index: linux-2.6.22-rc4-mm/arch/x86_64/kernel/time.c
===================================================================
@@ -255,7 +255,7 @@ static unsigned int __init tsc_calibrate
 
 static struct irqaction irq0 = {
 	.handler	= timer_interrupt,
-	.flags		= IRQF_DISABLED | IRQF_IRQPOLL,
+	.flags		= IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING,
 	.mask		= CPU_MASK_NONE,
 	.name		= "timer"
 };
#41 lore raw

PATCH 24/25 x86_64: prep idle loop for dynticks

In reply to Thomas Gleixner

From: Chris Wright <[email protected]>

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.

---
 arch/x86_64/kernel/process.c |    4 ++++
 1 file changed, 4 insertions(+)
arch/x86_64/kernel/process.c +4 -0
Index: linux-2.6.22-rc4-mm/arch/x86_64/kernel/process.c
===================================================================
@@ -37,6 +37,7 @@
 #include <linux/notifier.h>
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
+#include <linux/tick.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -207,6 +208,8 @@ void cpu_idle (void)
 			if (__get_cpu_var(cpu_idle_state))
 				__get_cpu_var(cpu_idle_state) = 0;
 
+			tick_nohz_stop_sched_tick();
+
 			check_pgt_cache();
 			rmb();
 			idle = pm_idle;
@@ -228,6 +231,7 @@ void cpu_idle (void)
 			__exit_idle();
 		}
 
+		tick_nohz_restart_sched_tick();
 		preempt_enable_no_resched();
 		schedule();
 		preempt_disable();
#42 lore raw

PATCH 25/25 x86_64: enable high resolution timers and dynticks

In reply to Thomas Gleixner

From: Chris Wright <[email protected]>

Everything is in place, enable the HIGHRES andf NO_HZ config options.

---
 arch/x86_64/Kconfig |    2 ++
 1 file changed, 2 insertions(+)
arch/x86_64/Kconfig +2 -0
Index: linux-2.6.22-rc4-mm/arch/x86_64/Kconfig
===================================================================
@@ -150,6 +150,8 @@ source "init/Kconfig"
 
 menu "Processor type and features"
 
+source "kernel/time/Kconfig"
+
 choice
 	prompt "Subarchitecture Type"
 	default X86_PC
#43 lore raw
In reply to Thomas Gleixner
Quoted 3 lines · On Saturday 16 June 2007 11:36:00 Thomas Gleixner wrote:

The -hrt tree at http://www.tglx.de/projects/hrtimers/2.6.22-rc4/ contains also an hpet force patch series from Venki Pallipadi, but I leave this up to Venki to send it mainline wards.

What's the status on the nForce "hpet force fix" (Subject: "Enable hidden HPET on NVidia motherboards") that also exists? I think if one board can have its HPET forced, so can another.

Last I heard we were waiting on NVIDIA to confirm whether Mikko's logic was supported by specifications? Any update on this?

Signature · 5 lines
Cheers,
Alistair.

Final year Computer Science undergraduate.
1F2 55 South Clerk Street, Edinburgh, UK.
#44 lore raw
Quoted 11 lines · Alistair John Strachan
Quoted 3 lines · On Saturday 16 June 2007 11:36:00 Thomas Gleixner wrote:

The -hrt tree at http://www.tglx.de/projects/hrtimers/2.6.22-rc4/ contains also an hpet force patch series from Venki Pallipadi, but I leave this up to Venki to send it mainline wards.

What's the status on the nForce "hpet force fix" (Subject: "Enable hidden HPET on NVidia motherboards") that also exists? I think if one board can have its HPET forced, so can another.

Last I heard we were waiting on NVIDIA to confirm whether Mikko's logic was supported by specifications? Any update on this?

The full hpet force enable series is maintained by Venki and updates should go to him. I can add the patch to my -hrt queue for testing.

tglx

#45 lore raw
In reply to Thomas Gleixner

Hi all.

I'm currently running with the combined patch applied all the time, and it seems to be working fine here, including with hibernation.

Regards,

Nigel

Signature · 4 lines
Nigel, Michelle and Alisdair Cunningham
5 Mitchell Street
Cobden 3266
Victoria, Australia
#46 lore raw
In reply to Thomas Gleixner
Quoted 7 lines · Thomas Gleixner

The following patch series contains:

- dyntick bugfixes for -mm (caused by the cpuidle changes in ACPI)

- updates and improvements to high resolution timer / dynticks

- high resolution timer / dynticks support for x86_64

Am running with the 22-rc4-mm2-hrt4 patch on my Latitude D820. Mostly seems to work, but for some reason the Intel 'powertop' util thinks it's 100% busy:

PowerTOP version 1.7 (C) 2007 Intel Corporation

Cn Avg residency (5s) P-states (frequencies)
C0 (cpu running) (100.0%)

C1                0.0ms ( 0.0%)         2.00 Ghz     0.0%
C2                0.0ms ( 0.0%)         1.67 Ghz     0.0%
C3                0.0ms ( 0.0%)         1333 Mhz     0.0%
                                        1000 Mhz   100.0%

In reality:

[/sys/devices/system/cpu/cpu0/cpuidle] for i in */*; do echo -n "$i: "; cat $i; done state0/latency: 1
state0/power: 1000
state0/time: 0
state0/usage: 3
state1/latency: 1
state1/power: 500
state1/time: 1756017623
state1/usage: 1837402
state2/latency: 57
state2/power: 100
state2/time: -159524787
state2/usage: 15007443

I think we have a 32/64 bit issue on state2/time which is probably borking things up....

#47 lore raw
Quoted 36 lines

-----Original Message-----
From: [email protected] [mailto:[email protected]]
Sent: Monday, June 18, 2007 1:07 PM
To: Thomas Gleixner
Cc: LKML; Andrew Morton; Ingo Molnar; Andi Kleen; Chris Wright; Arjan van de Ven; Pallipadi, Venkatesh
Subject: Re: [patch-mm 00/25] High resolution timer updates and x86_64 support - V2

Quoted 7 lines · Thomas Gleixner

The following patch series contains:

- dyntick bugfixes for -mm (caused by the cpuidle changes in ACPI)

- updates and improvements to high resolution timer / dynticks

- high resolution timer / dynticks support for x86_64

Am running with the 22-rc4-mm2-hrt4 patch on my Latitude D820. Mostly seems
to work, but for some reason the Intel 'powertop' util thinks it's 100% busy:

PowerTOP version 1.7 (C) 2007 Intel Corporation

Cn Avg residency (5s) P-states (frequencies)
C0 (cpu running) (100.0%)

C1                0.0ms ( 0.0%)         2.00 Ghz     0.0%
C2                0.0ms ( 0.0%)         1.67 Ghz     0.0%
C3                0.0ms ( 0.0%)         1333 Mhz     0.0%
                                       1000 Mhz   100.0%

In reality:

Quoted 15 lines

[/sys/devices/system/cpu/cpu0/cpuidle] for i in */*; do echo -n "$i: "; cat $i; done
state0/latency: 1
state0/power: 1000
state0/time: 0
state0/usage: 3
state1/latency: 1
state1/power: 500
state1/time: 1756017623
state1/usage: 1837402
state2/latency: 57
state2/power: 100
state2/time: -159524787
state2/usage: 15007443

The problem is powertop only understands /proc/acpi/processor/CPU*/power for
and not /sys..cpuidle for the moment.

I had a patch in recent cpuidle fixes series that makes /proc interface active
again with cpuidle which should correct this. Those patches are not in rc4-mm2-hrt4, but are there in latest rc4-hrt and rc5-hrt series.

Thanks,
Venki

#48 lore raw
Quoted 4 lines · Venkatesh
Quoted 3 lines

state2/time: -159524787
state2/usage: 15007443

Quoted 8 lines

The problem is powertop only understands /proc/acpi/processor/CPU*/power for
and not /sys..cpuidle for the moment.

I had a patch in recent cpuidle fixes series that makes /proc interface active
again with cpuidle which should correct this. Those patches are not in rc4-mm2-hrt4, but are there in latest rc4-hrt and rc5-hrt series.

OK, so I've got a 32/64 bug that isn't the cause of *this* issue because powertop isn't looking at the broken value.

A quick check shows that the keep_proc_acpi_power_around_001.patch from rc5-hrt will apply to rc4-mm2-hrt - I'll give that a try tonight and report back...

#49 lore raw
Quoted 24 lines

-----Original Message-----
From: [email protected] [mailto:[email protected]]
Sent: Monday, June 18, 2007 2:50 PM
To: Pallipadi, Venkatesh
Cc: Thomas Gleixner; LKML; Andrew Morton; Ingo Molnar; Andi Kleen; Chris Wright; Arjan van de Ven
Subject: Re: [patch-mm 00/25] High resolution timer updates and x86_64 support - V2

Quoted 5 lines · Venkatesh
Quoted 3 lines

state2/time: -159524787
state2/usage: 15007443

The problem is powertop only understands

/proc/acpi/processor/CPU*/power

Quoted 4 lines

for
and not /sys..cpuidle for the moment.

I had a patch in recent cpuidle fixes series that makes

/proc interface

Quoted 9 lines
Quoted 2 lines

active
again with cpuidle which should correct this. Those patches

are not in

Quoted 1 line

rc4-mm2-hrt4, but are there in latest rc4-hrt and rc5-hrt series.

OK, so I've got a 32/64 bug that isn't the cause of *this* issue because
powertop isn't looking at the broken value.

Yes. The output does indicate a bug in cpuidle /sysfs part. Will look at sysfs output of cpuidle and fix those issues soon.

Thanks,
Venki

#50 lore raw
In reply to [email protected]
Quoted 3 lines · On Mon, 18 Jun 2007 17:49:44 EDT, [email protected] said:

A quick check shows that the keep_proc_acpi_power_around_001.patch from rc5-hrt will apply to rc4-mm2-hrt - I'll give that a try tonight and report back...

Confirming - I backported that patch from rc5-hrt to rc4-mm2-hrt, and now powertop is reporting sane values again:

PowerTOP version 1.7 (C) 2007 Intel Corporation

Cn Avg residency (5s) P-states (frequencies)
C0 (cpu running) (15.8%)

C1                0.0ms ( 0.0%)         2.00 Ghz     0.0%
C2                0.6ms ( 7.9%)         1.67 Ghz     0.0%
C3                0.7ms (76.3%)         1333 Mhz     0.0%
                                        1000 Mhz   100.0%
#51 lore raw
In reply to [email protected]
Quoted 14 lines · On Mon, 2007-06-18 at 16:06 -0400, [email protected] wrote:
Quoted 7 lines · Thomas Gleixner

The following patch series contains:

- dyntick bugfixes for -mm (caused by the cpuidle changes in ACPI)

- updates and improvements to high resolution timer / dynticks

- high resolution timer / dynticks support for x86_64

Am running with the 22-rc4-mm2-hrt4 patch on my Latitude D820. Mostly seems to work, but for some reason the Intel 'powertop' util thinks it's 100% busy:

PowerTOP version 1.7 (C) 2007 Intel Corporation

Quoted 8 lines

Cn Avg residency (5s) P-states (frequencies)
C0 (cpu running) (100.0%)

C1                0.0ms ( 0.0%)         2.00 Ghz     0.0%
C2                0.0ms ( 0.0%)         1.67 Ghz     0.0%
C3                0.0ms ( 0.0%)         1333 Mhz     0.0%
                                        1000 Mhz   100.0%

In reality:

looks like something broke the /proc/acpi/processor/*/power file data....

can you check in that file to see if there is actual C-state time accounting going on?
(it is in mainline, so if it's not then it's an -mm or -hrt bug)

Signature · 2 lines
if you want to mail me at work (you don't), use arjan (at) linux.intel.com
Test the interaction between Linux and your BIOS via http://www.linuxfirmwarekit.org