summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/ppc/kernel/time.c25
-rw-r--r--arch/ppc64/kernel/time.c9
-rw-r--r--arch/sparc64/kernel/time.c20
-rw-r--r--arch/x86_64/kernel/time.c13
-rw-r--r--include/asm-ppc/time.h8
5 files changed, 73 insertions, 2 deletions
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
index b571bce80370..ee5072f60091 100644
--- a/arch/ppc/kernel/time.c
+++ b/arch/ppc/kernel/time.c
@@ -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 inscale, unsigned outscale) {
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 --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c
index 6657873853b3..2f5366cb9848 100644
--- a/arch/ppc64/kernel/time.c
+++ b/arch/ppc64/kernel/time.c
@@ -307,6 +307,15 @@ int timer_interrupt(struct pt_regs * regs)
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 --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index 2572fdcd9908..2039cf715782 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -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_cpufreq_notifier_block = {
#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_gettimeoffset(void)
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 --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index 92b8ffe633f6..315940661179 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -370,6 +370,19 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
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;
diff --git a/include/asm-ppc/time.h b/include/asm-ppc/time.h
index ff2939bcbcf9..67188ec06a7a 100644
--- a/include/asm-ppc/time.h
+++ b/include/asm-ppc/time.h
@@ -97,6 +97,13 @@ extern __inline__ unsigned long get_rtcl(void) {
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(void) {
#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;})