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/

Reply via email to