aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64
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
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')
-rw-r--r--arch/x86_64/Kconfig4
-rw-r--r--arch/x86_64/kernel/hpet.c6
-rw-r--r--arch/x86_64/kernel/time.c6
-rw-r--r--arch/x86_64/kernel/tsc.c7
-rw-r--r--arch/x86_64/kernel/vmlinux.lds.S28
-rw-r--r--arch/x86_64/kernel/vsyscall.c121
6 files changed, 100 insertions, 72 deletions
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index 286b4606fb1e..56eb14c98475 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -28,6 +28,10 @@ config GENERIC_TIME
28 bool 28 bool
29 default y 29 default y
30 30
31config GENERIC_TIME_VSYSCALL
32 bool
33 default y
34
31config ZONE_DMA32 35config ZONE_DMA32
32 bool 36 bool
33 default y 37 default y
diff --git a/arch/x86_64/kernel/hpet.c b/arch/x86_64/kernel/hpet.c
index c23738899ae9..65a0edd71a17 100644
--- a/arch/x86_64/kernel/hpet.c
+++ b/arch/x86_64/kernel/hpet.c
@@ -458,6 +458,11 @@ static cycle_t read_hpet(void)
458 return (cycle_t)readl(hpet_ptr); 458 return (cycle_t)readl(hpet_ptr);
459} 459}
460 460
461static cycle_t __vsyscall_fn vread_hpet(void)
462{
463 return readl((void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0);
464}
465
461struct clocksource clocksource_hpet = { 466struct clocksource clocksource_hpet = {
462 .name = "hpet", 467 .name = "hpet",
463 .rating = 250, 468 .rating = 250,
@@ -466,6 +471,7 @@ struct clocksource clocksource_hpet = {
466 .mult = 0, /* set below */ 471 .mult = 0, /* set below */
467 .shift = HPET_SHIFT, 472 .shift = HPET_SHIFT,
468 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 473 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
474 .vread = vread_hpet,
469}; 475};
470 476
471static int __init init_hpet_clocksource(void) 477static int __init init_hpet_clocksource(void)
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index d84208e3c618..a87c51705620 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -53,13 +53,7 @@ DEFINE_SPINLOCK(rtc_lock);
53EXPORT_SYMBOL(rtc_lock); 53EXPORT_SYMBOL(rtc_lock);
54DEFINE_SPINLOCK(i8253_lock); 54DEFINE_SPINLOCK(i8253_lock);
55 55
56unsigned long vxtime_hz = PIT_TICK_RATE;
57
58struct vxtime_data __vxtime __section_vxtime; /* for vsyscalls */
59
60volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES; 56volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
61struct timespec __xtime __section_xtime;
62struct timezone __sys_tz __section_sys_tz;
63 57
64unsigned long profile_pc(struct pt_regs *regs) 58unsigned long profile_pc(struct pt_regs *regs)
65{ 59{
diff --git a/arch/x86_64/kernel/tsc.c b/arch/x86_64/kernel/tsc.c
index 8c92f2fe7e2e..895831865019 100644
--- a/arch/x86_64/kernel/tsc.c
+++ b/arch/x86_64/kernel/tsc.c
@@ -180,6 +180,12 @@ static cycle_t read_tsc(void)
180 return ret; 180 return ret;
181} 181}
182 182
183static cycle_t __vsyscall_fn vread_tsc(void)
184{
185 cycle_t ret = (cycle_t)get_cycles_sync();
186 return ret;
187}
188
183static struct clocksource clocksource_tsc = { 189static struct clocksource clocksource_tsc = {
184 .name = "tsc", 190 .name = "tsc",
185 .rating = 300, 191 .rating = 300,
@@ -188,6 +194,7 @@ static struct clocksource clocksource_tsc = {
188 .shift = 22, 194 .shift = 22,
189 .flags = CLOCK_SOURCE_IS_CONTINUOUS | 195 .flags = CLOCK_SOURCE_IS_CONTINUOUS |
190 CLOCK_SOURCE_MUST_VERIFY, 196 CLOCK_SOURCE_MUST_VERIFY,
197 .vread = vread_tsc,
191}; 198};
192 199
193void mark_tsc_unstable(void) 200void mark_tsc_unstable(void)
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index c360c4225244..b73212c0a550 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -88,31 +88,25 @@ SECTIONS
88 __vsyscall_0 = VSYSCALL_VIRT_ADDR; 88 __vsyscall_0 = VSYSCALL_VIRT_ADDR;
89 89
90 . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); 90 . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
91 .xtime_lock : AT(VLOAD(.xtime_lock)) { *(.xtime_lock) } 91 .vsyscall_fn : AT(VLOAD(.vsyscall_fn)) { *(.vsyscall_fn) }
92 xtime_lock = VVIRT(.xtime_lock); 92 . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
93 93 .vsyscall_gtod_data : AT(VLOAD(.vsyscall_gtod_data))
94 .vxtime : AT(VLOAD(.vxtime)) { *(.vxtime) } 94 { *(.vsyscall_gtod_data) }
95 vxtime = VVIRT(.vxtime); 95 vsyscall_gtod_data = VVIRT(.vsyscall_gtod_data);
96 96
97 .vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) { *(.vgetcpu_mode) } 97 .vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) { *(.vgetcpu_mode) }
98 vgetcpu_mode = VVIRT(.vgetcpu_mode); 98 vgetcpu_mode = VVIRT(.vgetcpu_mode);
99 99
100 .sys_tz : AT(VLOAD(.sys_tz)) { *(.sys_tz) }
101 sys_tz = VVIRT(.sys_tz);
102
103 .sysctl_vsyscall : AT(VLOAD(.sysctl_vsyscall)) { *(.sysctl_vsyscall) }
104 sysctl_vsyscall = VVIRT(.sysctl_vsyscall);
105
106 .xtime : AT(VLOAD(.xtime)) { *(.xtime) }
107 xtime = VVIRT(.xtime);
108
109 . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); 100 . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
110 .jiffies : AT(VLOAD(.jiffies)) { *(.jiffies) } 101 .jiffies : AT(VLOAD(.jiffies)) { *(.jiffies) }
111 jiffies = VVIRT(.jiffies); 102 jiffies = VVIRT(.jiffies);
112 103
113 .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1)) { *(.vsyscall_1) } 104 .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1))
114 .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2)) { *(.vsyscall_2) } 105 { *(.vsyscall_1) }
115 .vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3)) { *(.vsyscall_3) } 106 .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2))
107 { *(.vsyscall_2) }
108 .vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3))
109 { *(.vsyscall_3) }
116 110
117 . = VSYSCALL_VIRT_ADDR + 4096; 111 . = VSYSCALL_VIRT_ADDR + 4096;
118 112
diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c
index 313dc6ad780b..180ff919eaf9 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 {}