

Ingo's CPU scheduler update (in -mm kernels) needs a new sched_clock()
function which returns nanoseconds.

The patch provides implementations for ppc, ppc64, x86_64 and sparc64.

The x86_64 version could have overflow issues, the calculation is done in
32bits only with an multiply.  But I hope it's good enough for the scheduler

The ppc64 version needs scaling: it's only accurate for 1GHz CPUs.



 25-akpm/arch/ppc/kernel/time.c     |   25 +++++++++++++++++++++++++
 25-akpm/arch/ppc64/kernel/time.c   |    9 +++++++++
 25-akpm/arch/sparc64/kernel/time.c |   20 ++++++++++++++++++--
 25-akpm/arch/x86_64/kernel/time.c  |   13 +++++++++++++
 25-akpm/include/asm-ppc/time.h     |    8 ++++++++
 5 files changed, 73 insertions(+), 2 deletions(-)

diff -puN arch/ppc/kernel/time.c~ppc-sched_clock arch/ppc/kernel/time.c
--- 25/arch/ppc/kernel/time.c~ppc-sched_clock	Thu Sep 18 16:53:56 2003
+++ 25-akpm/arch/ppc/kernel/time.c	Thu Sep 18 16:53:56 2003
@@ -83,6 +83,7 @@ time_t last_rtc_update;
 unsigned tb_ticks_per_jiffy;
 unsigned tb_to_us;
 unsigned tb_last_stamp;
+unsigned long tb_to_ns_scale;
 
 extern unsigned long wall_jiffies;
 
@@ -309,6 +310,7 @@ void __init time_init(void)
 		tb_to_us = 0x418937;
         } else {
                 ppc_md.calibrate_decr();
+		tb_to_ns_scale = mulhwu(tb_to_us, 1000 << 10);
 	}
 
 	/* Now that the decrementer is calibrated, it can be used in case the 
@@ -432,3 +434,26 @@ unsigned mulhwu_scale_factor(unsigned in
 	return mlt;
 }
 
+unsigned long long sched_clock(void)
+{
+	unsigned long lo, hi, hi2;
+	unsigned long long tb;
+
+	if (!__USE_RTC()) {
+		do {
+			hi = get_tbu();
+			lo = get_tbl();
+			hi2 = get_tbu();
+		} while (hi2 != hi);
+		tb = ((unsigned long long) hi << 32) | lo;
+		tb = (tb * tb_to_ns_scale) >> 10;
+	} else {
+		do {
+			hi = get_rtcu();
+			lo = get_rtcl();
+			hi2 = get_rtcu();
+		} while (hi2 != hi);
+		tb = ((unsigned long long) hi) * 1000000000 + lo;
+	}
+	return tb;
+}
diff -puN include/asm-ppc/time.h~ppc-sched_clock include/asm-ppc/time.h
--- 25/include/asm-ppc/time.h~ppc-sched_clock	Thu Sep 18 16:53:56 2003
+++ 25-akpm/include/asm-ppc/time.h	Thu Sep 18 16:53:56 2003
@@ -97,6 +97,13 @@ extern __inline__ unsigned long get_rtcl
 	return rtcl;
 }
 
+extern __inline__ unsigned long get_rtcu(void)
+{
+	unsigned long rtcu;
+	asm volatile("mfrtcu %0" : "=r" (rtcu));
+	return rtcu;
+}
+
 extern __inline__ unsigned get_native_tbl(void) {
 	if (__USE_RTC())
 		return get_rtcl();
@@ -140,6 +147,7 @@ extern __inline__ unsigned binary_tbl(vo
 #endif
 
 /* Use mulhwu to scale processor timebase to timeval */
+/* Specifically, this computes (x * y) / 2^32.  -- paulus */
 #define mulhwu(x,y) \
 ({unsigned z; asm ("mulhwu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;})
 
diff -puN arch/ppc64/kernel/time.c~ppc-sched_clock arch/ppc64/kernel/time.c
--- 25/arch/ppc64/kernel/time.c~ppc-sched_clock	Thu Sep 18 16:54:39 2003
+++ 25-akpm/arch/ppc64/kernel/time.c	Thu Sep 18 16:54:39 2003
@@ -307,6 +307,15 @@ int timer_interrupt(struct pt_regs * reg
 	return 1;
 }
 
+/*
+ * Scheduler clock - returns current time in nanosec units.
+ *
+ * This is wrong, but my CPUs run at 1GHz, so nyer nyer.
+ */
+unsigned long long sched_clock(void)
+{
+	return get_tb();
+}
 
 /*
  * This version of gettimeofday has microsecond resolution.
diff -puN arch/sparc64/kernel/time.c~ppc-sched_clock arch/sparc64/kernel/time.c
--- 25/arch/sparc64/kernel/time.c~ppc-sched_clock	Thu Sep 18 16:54:39 2003
+++ 25-akpm/arch/sparc64/kernel/time.c	Thu Sep 18 16:54:39 2003
@@ -416,6 +416,7 @@ unsigned long timer_tick_offset;
 unsigned long timer_tick_compare;
 
 static unsigned long timer_ticks_per_usec_quotient;
+static unsigned long timer_ticks_per_nsec_quotient;
 
 #define TICK_SIZE (tick_nsec / 1000)
 
@@ -1051,12 +1052,18 @@ static struct notifier_block sparc64_cpu
 #endif
 
 /* The quotient formula is taken from the IA64 port. */
+#define SPARC64_USEC_PER_CYC_SHIFT	30UL
+#define SPARC64_NSEC_PER_CYC_SHIFT	30UL
 void __init time_init(void)
 {
 	unsigned long clock = sparc64_init_timers(timer_interrupt);
 
 	timer_ticks_per_usec_quotient =
-		(((1000000UL << 30) +
+		(((1000000UL << SPARC64_USEC_PER_CYC_SHIFT) +
+		  (clock / 2)) / clock);
+
+	timer_ticks_per_nsec_quotient =
+		(((NSEC_PER_SEC << SPARC64_NSEC_PER_CYC_SHIFT) +
 		  (clock / 2)) / clock);
 
 #ifdef CONFIG_CPU_FREQ
@@ -1072,7 +1079,16 @@ static __inline__ unsigned long do_getti
 	ticks += timer_tick_offset;
 	ticks -= timer_tick_compare;
 
-	return (ticks * timer_ticks_per_usec_quotient) >> 30UL;
+	return (ticks * timer_ticks_per_usec_quotient)
+		>> SPARC64_USEC_PER_CYC_SHIFT;
+}
+
+unsigned long long sched_clock(void)
+{
+	unsigned long ticks = tick_ops->get_tick();
+
+	return (ticks * timer_ticks_per_nsec_quotient)
+		>> SPARC64_NSEC_PER_CYC_SHIFT;
 }
 
 int do_settimeofday(struct timespec *tv)
diff -puN arch/x86_64/kernel/time.c~ppc-sched_clock arch/x86_64/kernel/time.c
--- 25/arch/x86_64/kernel/time.c~ppc-sched_clock	Thu Sep 18 16:54:39 2003
+++ 25-akpm/arch/x86_64/kernel/time.c	Thu Sep 18 16:54:39 2003
@@ -370,6 +370,19 @@ static irqreturn_t timer_interrupt(int i
 	return IRQ_HANDLED;
 }
 
+/* RED-PEN: calculation is done in 32bits with multiply for performance
+   and could overflow, it may be better (but slower)to use an 64bit division. */
+unsigned long long sched_clock(void)
+{
+	unsigned long a;
+
+	if (__vxtime.mode == VXTIME_HPET)
+		return (hpet_readl(HPET_COUNTER) * vxtime.quot) >> 32;
+
+	rdtscll(a);
+	return (a * vxtime.tsc_quot) >> 32;
+}
+
 unsigned long get_cmos_time(void)
 {
 	unsigned int timeout, year, mon, day, hour, min, sec;

_
