Re: [patch 00/46] High resolution timer / dynamic tick update

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 2007-01-24 at 17:00 +0100, Ingo Molnar wrote:
> you are also misunderstand the change. While the TSC is the only 
> unstable clocksource right now, the previous code tied the TSC to the
> >pm-timer< clocksource. This change makes it generic, hence the TSC can
> be verified by a hpet-only system (no pm-timer) as well. Systems without 
> a pm-timer and with a TSC are quite common. So it solves a real problem.

Here is an example of what I was talking about in my last email . This
is a TSC specific clock verify ontop of -mm + my patches. It will use
and acpi_pm or and hpet (or pit or whatever) . Clearly the
implementation details could be worked on but the clock access would
remain largely the same.

Signed-Off-By: Daniel Walker <[email protected]>

---
 arch/i386/kernel/tsc.c      |   93 ++++++++++++++++++++------------------------
 include/linux/clocksource.h |    5 ++
 2 files changed, 49 insertions(+), 49 deletions(-)

Index: linux-2.6.19/arch/i386/kernel/tsc.c
===================================================================
--- linux-2.6.19.orig/arch/i386/kernel/tsc.c
+++ linux-2.6.19/arch/i386/kernel/tsc.c
@@ -343,7 +343,7 @@ static struct clocksource clocksource_ts
 	.mask			= CLOCKSOURCE_MASK(64),
 	.mult			= 0, /* to be set */
 	.shift			= 22,
-	.flags			= CLOCKSOURCE_64BITS,
+	.flags			= CLOCKSOURCE_64BITS | CLOCKSOURCE_PM_AFFECTED,
 	.list			= LIST_HEAD_INIT(clocksource_tsc.list),
 };
 
@@ -382,55 +382,54 @@ static struct dmi_system_id __initdata b
 	 {}
 };
 
-#define TSC_FREQ_CHECK_INTERVAL MSEC_PER_SEC
+#define WATCHDOG_TRESHOLD (NSEC_PER_SEC >> 4)
+#define TSC_FREQ_CHECK_INTERVAL (MSEC_PER_SEC/2)
 static struct timer_list verify_tsc_freq_timer;
 static unsigned long pm_multiplier;
+struct clocksource *verify_clock;
+
 
 /* XXX - Probably should add locking */
 static void verify_tsc_freq(unsigned long unused)
 {
-	static u64 last_tsc;
-	static unsigned long last_jiffies, last_pm;
+	static unsigned long last_jiffies;
+	static cycle_t last_tsc, last_verify;
 
-	u64 now_tsc, interval_tsc, tmp;
-	unsigned long now_jiffies, interval_jiffies, pm, pm_delta;
+	cycle_t now_tsc, interval_tsc, verify_clock_now, interval_verify;
+	unsigned long now_jiffies, interval_jiffies;
+	s64 ns_tsc, ns_verify, clock_diff;
 
 	if (check_tsc_unstable())
 		return;
 
-	rdtscll(now_tsc);
 	now_jiffies = jiffies;
-	pm = acpi_pm_read_early();
+
+	now_tsc = clocksource_read(&clocksource_tsc);
+	verify_clock_now = clocksource_read(verify_clock);
 
 	if (!last_jiffies)
 		goto out;
 
-	interval_tsc = now_tsc - last_tsc;
-	interval_tsc *= HZ;
-	do_div(interval_tsc, cpu_khz*1000);
-
-	if (pm == last_pm) {
-		interval_jiffies = now_jiffies - last_jiffies;
-	} else {
-		if (pm < last_pm)
-			pm_delta = (pm + ACPI_PM_OVRRUN) - last_pm;
-		else
-			pm_delta = pm - last_pm;
-		tmp = (((u64) pm_delta) * pm_multiplier) >> 22;
-		do_div(tmp, (NSEC_PER_SEC/HZ));
-		interval_jiffies = (unsigned long) tmp;
-	}
 
-	if (interval_tsc < (interval_jiffies * 3 / 4)) {
+	interval_tsc = clocksource_subtract(&clocksource_tsc, last_tsc, now_tsc);
+	interval_verify = clocksource_subtract(verify_clock, last_verify,
+					       verify_clock_now);
+
+	ns_tsc = cyc2ns(&clocksource_tsc, interval_tsc);
+	ns_verify = cyc2ns(verify_clock, interval_verify);
+
+	clock_diff = ns_tsc - ns_verify;
+	if (abs(clock_diff) > WATCHDOG_TRESHOLD) {
 		printk("TSC appears to be running slowly. "
-		       "Marking it as unstable\n");
+		       "Marking it as unstable");
 		mark_tsc_unstable();
 		return;
 	}
 out:
 	last_tsc = now_tsc;
 	last_jiffies = now_jiffies;
-	last_pm = pm;
+	last_verify = verify_clock_now;
+
 	/* set us up to go off on the next interval: */
 	mod_timer(&verify_tsc_freq_timer,
 		jiffies + msecs_to_jiffies(TSC_FREQ_CHECK_INTERVAL));
@@ -471,29 +470,6 @@ static int __init init_tsc_clocksource(v
 		if (check_tsc_unstable())
 			clocksource_tsc.flags |= CLOCKSOURCE_UNSTABLE;
 
-		/*
-		 * Mark TSC unsuitable for high resolution timers, when
-		 * pm_timer is not available as a fallback. TSC has so many
-		 * pitfalls: frequency changes, stop in idle ...  When we
-		 * switch to high resolution mode we can not longer detect a
-		 * firmware caused frequency change, as the emulated tick uses
-		 * TSC as reference. This results in a circular dependency.
-		 * Switch only to high resolution mode, if pm_timer or such is
-		 * available.
-		 */
-		if (!pmtmr_ioport) {
-			mark_tsc_unstable();
-			clocksource_tsc.flags &= CLOCKSOURCE_UNSTABLE;
-		}
-
-		pm_multiplier = clocksource_hz2mult(PMTMR_TICKS_PER_SEC, 22);
-
-		init_timer(&verify_tsc_freq_timer);
-		verify_tsc_freq_timer.function = verify_tsc_freq;
-		verify_tsc_freq_timer.expires =
-			jiffies + msecs_to_jiffies(TSC_FREQ_CHECK_INTERVAL);
-		add_timer(&verify_tsc_freq_timer);
-
 		return clocksource_register(&clocksource_tsc);
 	}
 
@@ -501,3 +477,22 @@ static int __init init_tsc_clocksource(v
 }
 
 fs_initcall(init_tsc_clocksource);
+
+void tsc_verify_init(void)
+{
+	verify_clock = clocksource_get_clock(NULL, CLOCKSOURCE_PM_AFFECTED);
+	if (!verify_clock) {
+		printk("TSC: Verify clock not found!\n");
+		return;
+	}
+
+	printk("TSC: selected %s for TSC verification\n", verify_clock->name);
+
+	init_timer(&verify_tsc_freq_timer);
+	verify_tsc_freq_timer.function = verify_tsc_freq;
+	verify_tsc_freq_timer.expires =
+		jiffies + msecs_to_jiffies(TSC_FREQ_CHECK_INTERVAL);
+	add_timer(&verify_tsc_freq_timer);
+
+}
+device_initcall(tsc_verify_init);
Index: linux-2.6.19/include/linux/clocksource.h
===================================================================
--- linux-2.6.19.orig/include/linux/clocksource.h
+++ linux-2.6.19/include/linux/clocksource.h
@@ -207,6 +207,11 @@ static inline s64 cyc2ns(struct clocksou
 	return ret;
 }
 
+static inline s64 clocksource_subtract(struct clocksource* cs, s64 start, s64 stop)
+{
+	return ((stop - start) & cs->mask);
+}
+
 /**
  * clocksource_calculate_interval - Calculates a clocksource interval struct
  *


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux