Commit 1c41006f authored by Andi Kleen's avatar Andi Kleen Committed by Linus Torvalds

[PATCH] Time changes for x86-64

Some timer updates from Vojtech Pavlik for x86-64.  In theory support
HPET timing now, but the support is disabled.

Would actually need vxtime_lock() macros in the generic timer code to
protect xtime updates, but I'm leaving that out now because it's only
needed for vsyscalls and they're currently disabled.
parent 15aed72d
This diff is collapsed.
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
#define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr))) #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
//#define NO_VSYSCALL 1 #define NO_VSYSCALL 1
#ifdef NO_VSYSCALL #ifdef NO_VSYSCALL
#include <asm/unistd.h> #include <asm/unistd.h>
...@@ -71,51 +71,27 @@ static inline void timeval_normalize(struct timeval * tv) ...@@ -71,51 +71,27 @@ static inline void timeval_normalize(struct timeval * tv)
long __vxtime_sequence[2] __section_vxtime_sequence; long __vxtime_sequence[2] __section_vxtime_sequence;
static inline void do_vgettimeofday(struct timeval * tv) static inline void do_vgettimeofday(struct timeval * tv)
{ {
long sequence; long sequence, t;
unsigned long usec, sec; unsigned long sec, usec;
do { do {
unsigned long eax, edx;
sequence = __vxtime_sequence[1]; sequence = __vxtime_sequence[1];
rmb(); rmb();
/* Read the Time Stamp Counter */ rdtscll(t);
rdtsc(eax,edx);
/* .. relative to previous jiffy (32 bits is enough) */
eax -= __last_tsc_low; /* tsc_low delta */
/*
* Time offset = (tsc_low delta) * fast_gettimeoffset_quotient
* = (tsc_low delta) * (usecs_per_clock)
* = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy)
*
* Using a mull instead of a divl saves up to 31 clock cycles
* in the critical path.
*/
edx = (eax*__fast_gettimeoffset_quotient) >> 32;
/* our adjusted time offset in microseconds */
usec = __delay_at_last_interrupt + edx;
{
unsigned long lost = __jiffies - __wall_jiffies;
if (lost)
usec += lost * (1000000 / HZ);
}
sec = __xtime.tv_sec; sec = __xtime.tv_sec;
usec += __xtime.tv_usec; usec = __xtime.tv_usec +
(__jiffies - __wall_jiffies) * (1000000 / HZ) +
(t - __hpet.last_tsc) * (1000000 / HZ) / __hpet.ticks + __hpet.offset;
rmb(); rmb();
} while (sequence != __vxtime_sequence[0]); } while (sequence != __vxtime_sequence[0]);
tv->tv_sec = sec; tv->tv_sec = sec + usec / 1000000;
tv->tv_usec = usec; tv->tv_usec = usec % 1000000;
timeval_normalize(tv);
} }
static inline void do_get_tz(struct timezone * tz) static inline void do_get_tz(struct timezone * tz)
......
...@@ -36,16 +36,14 @@ extern cycles_t cacheflush_time; ...@@ -36,16 +36,14 @@ extern cycles_t cacheflush_time;
static inline cycles_t get_cycles (void) static inline cycles_t get_cycles (void)
{ {
#ifndef CONFIG_X86_TSC
return 0;
#else
unsigned long long ret; unsigned long long ret;
rdtscll(ret); rdtscll(ret);
return ret; return ret;
#endif
} }
extern unsigned int cpu_khz; extern unsigned int cpu_khz;
extern struct hpet_data hpet;
#endif #endif
#ifndef _ASM_X86_64_VSYSCALL_H_ #ifndef _ASM_X86_64_VSYSCALL_H_
#define _ASM_X86_64_VSYSCALL_H_ #define _ASM_X86_64_VSYSCALL_H_
#include <linux/time.h>
enum vsyscall_num { enum vsyscall_num {
__NR_vgettimeofday, __NR_vgettimeofday,
__NR_vtime, __NR_vtime,
...@@ -13,32 +15,39 @@ enum vsyscall_num { ...@@ -13,32 +15,39 @@ enum vsyscall_num {
#ifdef __KERNEL__ #ifdef __KERNEL__
#define __section_last_tsc_low __attribute__ ((unused, __section__ (".last_tsc_low"))) #define __section_hpet __attribute__ ((unused, __section__ (".hpet"), aligned(16)))
#define __section_delay_at_last_interrupt __attribute__ ((unused, __section__ (".delay_at_last_interrupt"))) #define __section_wall_jiffies __attribute__ ((unused, __section__ (".wall_jiffies"), aligned(16)))
#define __section_fast_gettimeoffset_quotient __attribute__ ((unused, __section__ (".fast_gettimeoffset_quotient"))) #define __section_jiffies __attribute__ ((unused, __section__ (".jiffies"), aligned(16)))
#define __section_wall_jiffies __attribute__ ((unused, __section__ (".wall_jiffies"))) #define __section_sys_tz __attribute__ ((unused, __section__ (".sys_tz"), aligned(16)))
#define __section_jiffies __attribute__ ((unused, __section__ (".jiffies"))) #define __section_xtime __attribute__ ((unused, __section__ (".xtime"), aligned(16)))
#define __section_sys_tz __attribute__ ((unused, __section__ (".sys_tz"))) #define __section_vxtime_sequence __attribute__ ((unused, __section__ (".vxtime_sequence"), aligned(16)))
#define __section_xtime __attribute__ ((unused, __section__ (".xtime")))
#define __section_vxtime_sequence __attribute__ ((unused, __section__ (".vxtime_sequence"))) struct hpet_data {
long address; /* base address */
unsigned long hz; /* HPET clocks / sec */
int trigger; /* value at last interrupt */
int last;
int offset;
unsigned long last_tsc;
long ticks;
};
#define hpet_readl(a) readl(fix_to_virt(FIX_HPET_BASE) + a)
#define hpet_writel(d,a) writel(d, fix_to_virt(FIX_HPET_BASE) + a)
/* vsyscall space (readonly) */ /* vsyscall space (readonly) */
extern long __vxtime_sequence[2]; extern long __vxtime_sequence[2];
extern int __delay_at_last_interrupt; extern struct hpet_data __hpet;
extern unsigned int __last_tsc_low; extern struct timespec __xtime;
extern unsigned int __fast_gettimeoffset_quotient;
extern struct timeval __xtime;
extern volatile unsigned long __jiffies; extern volatile unsigned long __jiffies;
extern unsigned long __wall_jiffies; extern unsigned long __wall_jiffies;
extern struct timezone __sys_tz; extern struct timezone __sys_tz;
/* kernel space (writeable) */ /* kernel space (writeable) */
extern unsigned long last_tsc_low; extern long vxtime_sequence[2];
extern int delay_at_last_interrupt; extern struct hpet_data hpet;
extern unsigned int fast_gettimeoffset_quotient;
extern unsigned long wall_jiffies; extern unsigned long wall_jiffies;
extern struct timezone sys_tz; extern struct timezone sys_tz;
extern long vxtime_sequence[2];
#define vxtime_lock() do { vxtime_sequence[0]++; wmb(); } while(0) #define vxtime_lock() do { vxtime_sequence[0]++; wmb(); } while(0)
#define vxtime_unlock() do { wmb(); vxtime_sequence[1]++; } while (0) #define vxtime_unlock() do { wmb(); vxtime_sequence[1]++; } while (0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment