From: john stultz Here is the monotonic_clock() interface for AMD64. This implements the function for both TSC and HPET time sources. arch/x86_64/kernel/time.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 47 insertions(+) diff -puN arch/x86_64/kernel/time.c~amd64-monotonic-clock arch/x86_64/kernel/time.c --- 25/arch/x86_64/kernel/time.c~amd64-monotonic-clock 2003-06-23 22:53:55.000000000 -0700 +++ 25-akpm/arch/x86_64/kernel/time.c 2003-06-23 22:53:55.000000000 -0700 @@ -47,6 +47,7 @@ unsigned long hpet_period; /* fsecs / unsigned long hpet_tick; /* HPET clocks / interrupt */ unsigned long vxtime_hz = 1193182; int report_lost_ticks; /* command line option */ +unsigned long long monotonic_base; struct vxtime_data __vxtime __section_vxtime; /* for vsyscalls */ @@ -219,6 +220,47 @@ static void set_rtc_mmss(unsigned long n spin_unlock(&rtc_lock); } + +/* monotonic_clock(): returns # of nanoseconds passed since time_init() + * Note: This function is required to return accurate + * time even in the absence of multiple timer ticks. + */ +unsigned long long monotonic_clock(void) +{ + unsigned long seq; + u32 last_offset, this_offset, offset; + unsigned long long base; + + if (vxtime.mode == VXTIME_HPET) { + do { + seq = read_seqbegin(&xtime_lock); + + last_offset = vxtime.last; + base = monotonic_base; + this_offset = hpet_readl(HPET_T0_CMP) - hpet_tick; + + } while (read_seqretry(&xtime_lock, seq)); + offset = (this_offset - last_offset); + offset *=(NSEC_PER_SEC/HZ)/hpet_tick; + return base + offset; + }else{ + do { + seq = read_seqbegin(&xtime_lock); + + last_offset = vxtime.last_tsc; + base = monotonic_base; + } while (read_seqretry(&xtime_lock, seq)); + sync_core(); + rdtscll(this_offset); + offset = (this_offset - last_offset)*1000/cpu_khz; + return base + offset; + } + + +} +EXPORT_SYMBOL(monotonic_clock); + + static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { static unsigned long rtc_update = 0; @@ -252,6 +294,9 @@ static irqreturn_t timer_interrupt(int i if (offset - vxtime.last > hpet_tick) { lost = (offset - vxtime.last) / hpet_tick - 1; } + + monotonic_base += + (offset - vxtime.last)*(NSEC_PER_SEC/HZ) / hpet_tick; vxtime.last = offset; } else { @@ -266,6 +311,8 @@ static irqreturn_t timer_interrupt(int i offset %= (USEC_PER_SEC / HZ); } + monotonic_base += (tsc - vxtime.last_tsc)*1000000/cpu_khz ; + vxtime.last_tsc = tsc - vxtime.quot * delay / vxtime.tsc_quot; if ((((tsc - vxtime.last_tsc) * _