aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/vsyscall.c
diff options
context:
space:
mode:
authorjohn stultz <johnstul@us.ibm.com>2007-02-16 04:28:21 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-16 11:14:00 -0500
commit7460ed2844ffad7141e30271c0c3da8336e66014 (patch)
tree4ae7f2ebf09b59f214d243d0f886fb2c4e7915e8 /arch/x86_64/kernel/vsyscall.c
parent1489939f0ab64b96998e04068c516c39afe29654 (diff)
[PATCH] time: x86_64: re-enable vsyscall support for x86_64
Cleanup and re-enable vsyscall gettimeofday using the generic clocksource infrastructure. [akpm@osdl.org: cleanup] Signed-off-by: John Stultz <johnstul@us.ibm.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Andi Kleen <ak@muc.de> Cc: Roman Zippel <zippel@linux-m68k.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/x86_64/kernel/vsyscall.c')
-rw-r--r--arch/x86_64/kernel/vsyscall.c121
1 files changed, 72 insertions, 49 deletions
diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c
index 313dc6ad780..180ff919eaf 100644
--- a/arch/x86_64/kernel/vsyscall.c
+++ b/arch/x86_64/kernel/vsyscall.c
@@ -26,6 +26,7 @@
26#include <linux/seqlock.h> 26#include <linux/seqlock.h>
27#include <linux/jiffies.h> 27#include <linux/jiffies.h>
28#include <linux/sysctl.h> 28#include <linux/sysctl.h>
29#include <linux/clocksource.h>
29#include <linux/getcpu.h> 30#include <linux/getcpu.h>
30#include <linux/cpu.h> 31#include <linux/cpu.h>
31#include <linux/smp.h> 32#include <linux/smp.h>
@@ -34,6 +35,7 @@
34#include <asm/vsyscall.h> 35#include <asm/vsyscall.h>
35#include <asm/pgtable.h> 36#include <asm/pgtable.h>
36#include <asm/page.h> 37#include <asm/page.h>
38#include <asm/unistd.h>
37#include <asm/fixmap.h> 39#include <asm/fixmap.h>
38#include <asm/errno.h> 40#include <asm/errno.h>
39#include <asm/io.h> 41#include <asm/io.h>
@@ -44,56 +46,41 @@
44#define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr))) 46#define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
45#define __syscall_clobber "r11","rcx","memory" 47#define __syscall_clobber "r11","rcx","memory"
46 48
47int __sysctl_vsyscall __section_sysctl_vsyscall = 1; 49struct vsyscall_gtod_data_t {
48seqlock_t __xtime_lock __section_xtime_lock = SEQLOCK_UNLOCKED; 50 seqlock_t lock;
51 int sysctl_enabled;
52 struct timeval wall_time_tv;
53 struct timezone sys_tz;
54 cycle_t offset_base;
55 struct clocksource clock;
56};
49int __vgetcpu_mode __section_vgetcpu_mode; 57int __vgetcpu_mode __section_vgetcpu_mode;
50 58
51#include <asm/unistd.h> 59struct vsyscall_gtod_data_t __vsyscall_gtod_data __section_vsyscall_gtod_data =
52
53static __always_inline void timeval_normalize(struct timeval * tv)
54{ 60{
55 time_t __sec; 61 .lock = SEQLOCK_UNLOCKED,
56 62 .sysctl_enabled = 1,
57 __sec = tv->tv_usec / 1000000; 63};
58 if (__sec) {
59 tv->tv_usec %= 1000000;
60 tv->tv_sec += __sec;
61 }
62}
63 64
64static __always_inline void do_vgettimeofday(struct timeval * tv) 65void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
65{ 66{
66 long sequence, t; 67 unsigned long flags;
67 unsigned long sec, usec; 68
68 69 write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags);
69 do { 70 /* copy vsyscall data */
70 sequence = read_seqbegin(&__xtime_lock); 71 vsyscall_gtod_data.clock = *clock;
71 72 vsyscall_gtod_data.wall_time_tv.tv_sec = wall_time->tv_sec;
72 sec = __xtime.tv_sec; 73 vsyscall_gtod_data.wall_time_tv.tv_usec = wall_time->tv_nsec/1000;
73 usec = __xtime.tv_nsec / 1000; 74 vsyscall_gtod_data.sys_tz = sys_tz;
74 75 write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
75 if (__vxtime.mode != VXTIME_HPET) {
76 t = get_cycles_sync();
77 if (t < __vxtime.last_tsc)
78 t = __vxtime.last_tsc;
79 usec += ((t - __vxtime.last_tsc) *
80 __vxtime.tsc_quot) >> 32;
81 /* See comment in x86_64 do_gettimeofday. */
82 } else {
83 usec += ((readl((void __iomem *)
84 fix_to_virt(VSYSCALL_HPET) + 0xf0) -
85 __vxtime.last) * __vxtime.quot) >> 32;
86 }
87 } while (read_seqretry(&__xtime_lock, sequence));
88
89 tv->tv_sec = sec + usec / 1000000;
90 tv->tv_usec = usec % 1000000;
91} 76}
92 77
93/* RED-PEN may want to readd seq locking, but then the variable should be write-once. */ 78/* RED-PEN may want to readd seq locking, but then the variable should be
79 * write-once.
80 */
94static __always_inline void do_get_tz(struct timezone * tz) 81static __always_inline void do_get_tz(struct timezone * tz)
95{ 82{
96 *tz = __sys_tz; 83 *tz = __vsyscall_gtod_data.sys_tz;
97} 84}
98 85
99static __always_inline int gettimeofday(struct timeval *tv, struct timezone *tz) 86static __always_inline int gettimeofday(struct timeval *tv, struct timezone *tz)
@@ -101,7 +88,8 @@ static __always_inline int gettimeofday(struct timeval *tv, struct timezone *tz)
101 int ret; 88 int ret;
102 asm volatile("vsysc2: syscall" 89 asm volatile("vsysc2: syscall"
103 : "=a" (ret) 90 : "=a" (ret)
104 : "0" (__NR_gettimeofday),"D" (tv),"S" (tz) : __syscall_clobber ); 91 : "0" (__NR_gettimeofday),"D" (tv),"S" (tz)
92 : __syscall_clobber );
105 return ret; 93 return ret;
106} 94}
107 95
@@ -114,10 +102,44 @@ static __always_inline long time_syscall(long *t)
114 return secs; 102 return secs;
115} 103}
116 104
105static __always_inline void do_vgettimeofday(struct timeval * tv)
106{
107 cycle_t now, base, mask, cycle_delta;
108 unsigned long seq, mult, shift, nsec_delta;
109 cycle_t (*vread)(void);
110 do {
111 seq = read_seqbegin(&__vsyscall_gtod_data.lock);
112
113 vread = __vsyscall_gtod_data.clock.vread;
114 if (unlikely(!__vsyscall_gtod_data.sysctl_enabled || !vread)) {
115 gettimeofday(tv,0);
116 return;
117 }
118 now = vread();
119 base = __vsyscall_gtod_data.clock.cycle_last;
120 mask = __vsyscall_gtod_data.clock.mask;
121 mult = __vsyscall_gtod_data.clock.mult;
122 shift = __vsyscall_gtod_data.clock.shift;
123
124 *tv = __vsyscall_gtod_data.wall_time_tv;
125
126 } while (read_seqretry(&__vsyscall_gtod_data.lock, seq));
127
128 /* calculate interval: */
129 cycle_delta = (now - base) & mask;
130 /* convert to nsecs: */
131 nsec_delta = (cycle_delta * mult) >> shift;
132
133 /* convert to usecs and add to timespec: */
134 tv->tv_usec += nsec_delta / NSEC_PER_USEC;
135 while (tv->tv_usec > USEC_PER_SEC) {
136 tv->tv_sec += 1;
137 tv->tv_usec -= USEC_PER_SEC;
138 }
139}
140
117int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz) 141int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
118{ 142{
119 if (!__sysctl_vsyscall)
120 return gettimeofday(tv,tz);
121 if (tv) 143 if (tv)
122 do_vgettimeofday(tv); 144 do_vgettimeofday(tv);
123 if (tz) 145 if (tz)
@@ -129,11 +151,11 @@ int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
129 * unlikely */ 151 * unlikely */
130time_t __vsyscall(1) vtime(time_t *t) 152time_t __vsyscall(1) vtime(time_t *t)
131{ 153{
132 if (!__sysctl_vsyscall) 154 if (unlikely(!__vsyscall_gtod_data.sysctl_enabled))
133 return time_syscall(t); 155 return time_syscall(t);
134 else if (t) 156 else if (t)
135 *t = __xtime.tv_sec; 157 *t = __vsyscall_gtod_data.wall_time_tv.tv_sec;
136 return __xtime.tv_sec; 158 return __vsyscall_gtod_data.wall_time_tv.tv_sec;
137} 159}
138 160
139/* Fast way to get current CPU and node. 161/* Fast way to get current CPU and node.
@@ -210,7 +232,7 @@ static int vsyscall_sysctl_change(ctl_table *ctl, int write, struct file * filp,
210 ret = -ENOMEM; 232 ret = -ENOMEM;
211 goto out; 233 goto out;
212 } 234 }
213 if (!sysctl_vsyscall) { 235 if (!vsyscall_gtod_data.sysctl_enabled) {
214 writew(SYSCALL, map1); 236 writew(SYSCALL, map1);
215 writew(SYSCALL, map2); 237 writew(SYSCALL, map2);
216 } else { 238 } else {
@@ -232,7 +254,8 @@ static int vsyscall_sysctl_nostrat(ctl_table *t, int __user *name, int nlen,
232 254
233static ctl_table kernel_table2[] = { 255static ctl_table kernel_table2[] = {
234 { .ctl_name = 99, .procname = "vsyscall64", 256 { .ctl_name = 99, .procname = "vsyscall64",
235 .data = &sysctl_vsyscall, .maxlen = sizeof(int), .mode = 0644, 257 .data = &vsyscall_gtod_data.sysctl_enabled, .maxlen = sizeof(int),
258 .mode = 0644,
236 .strategy = vsyscall_sysctl_nostrat, 259 .strategy = vsyscall_sysctl_nostrat,
237 .proc_handler = vsyscall_sysctl_change }, 260 .proc_handler = vsyscall_sysctl_change },
238 {} 261 {}