diff options
Diffstat (limited to 'arch/x86_64/kernel/time.c')
-rw-r--r-- | arch/x86_64/kernel/time.c | 87 |
1 files changed, 41 insertions, 46 deletions
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 7392570f975d..ebbee6f59ff5 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c | |||
@@ -8,7 +8,7 @@ | |||
8 | * Copyright (c) 1995 Markus Kuhn | 8 | * Copyright (c) 1995 Markus Kuhn |
9 | * Copyright (c) 1996 Ingo Molnar | 9 | * Copyright (c) 1996 Ingo Molnar |
10 | * Copyright (c) 1998 Andrea Arcangeli | 10 | * Copyright (c) 1998 Andrea Arcangeli |
11 | * Copyright (c) 2002 Vojtech Pavlik | 11 | * Copyright (c) 2002,2006 Vojtech Pavlik |
12 | * Copyright (c) 2003 Andi Kleen | 12 | * Copyright (c) 2003 Andi Kleen |
13 | * RTC support code taken from arch/i386/kernel/timers/time_hpet.c | 13 | * RTC support code taken from arch/i386/kernel/timers/time_hpet.c |
14 | */ | 14 | */ |
@@ -51,14 +51,21 @@ extern int using_apic_timer; | |||
51 | static char *time_init_gtod(void); | 51 | static char *time_init_gtod(void); |
52 | 52 | ||
53 | DEFINE_SPINLOCK(rtc_lock); | 53 | DEFINE_SPINLOCK(rtc_lock); |
54 | EXPORT_SYMBOL(rtc_lock); | ||
54 | DEFINE_SPINLOCK(i8253_lock); | 55 | DEFINE_SPINLOCK(i8253_lock); |
55 | 56 | ||
56 | int nohpet __initdata = 0; | 57 | int nohpet __initdata = 0; |
57 | static int notsc __initdata = 0; | 58 | static int notsc __initdata = 0; |
58 | 59 | ||
59 | #undef HPET_HACK_ENABLE_DANGEROUS | 60 | #define USEC_PER_TICK (USEC_PER_SEC / HZ) |
61 | #define NSEC_PER_TICK (NSEC_PER_SEC / HZ) | ||
62 | #define FSEC_PER_TICK (FSEC_PER_SEC / HZ) | ||
63 | |||
64 | #define NS_SCALE 10 /* 2^10, carefully chosen */ | ||
65 | #define US_SCALE 32 /* 2^32, arbitralrily chosen */ | ||
60 | 66 | ||
61 | unsigned int cpu_khz; /* TSC clocks / usec, not used here */ | 67 | unsigned int cpu_khz; /* TSC clocks / usec, not used here */ |
68 | EXPORT_SYMBOL(cpu_khz); | ||
62 | static unsigned long hpet_period; /* fsecs / HPET clock */ | 69 | static unsigned long hpet_period; /* fsecs / HPET clock */ |
63 | unsigned long hpet_tick; /* HPET clocks / interrupt */ | 70 | unsigned long hpet_tick; /* HPET clocks / interrupt */ |
64 | int hpet_use_timer; /* Use counter of hpet for time keeping, otherwise PIT */ | 71 | int hpet_use_timer; /* Use counter of hpet for time keeping, otherwise PIT */ |
@@ -90,7 +97,7 @@ static inline unsigned int do_gettimeoffset_tsc(void) | |||
90 | t = get_cycles_sync(); | 97 | t = get_cycles_sync(); |
91 | if (t < vxtime.last_tsc) | 98 | if (t < vxtime.last_tsc) |
92 | t = vxtime.last_tsc; /* hack */ | 99 | t = vxtime.last_tsc; /* hack */ |
93 | x = ((t - vxtime.last_tsc) * vxtime.tsc_quot) >> 32; | 100 | x = ((t - vxtime.last_tsc) * vxtime.tsc_quot) >> US_SCALE; |
94 | return x; | 101 | return x; |
95 | } | 102 | } |
96 | 103 | ||
@@ -98,7 +105,7 @@ static inline unsigned int do_gettimeoffset_hpet(void) | |||
98 | { | 105 | { |
99 | /* cap counter read to one tick to avoid inconsistencies */ | 106 | /* cap counter read to one tick to avoid inconsistencies */ |
100 | unsigned long counter = hpet_readl(HPET_COUNTER) - vxtime.last; | 107 | unsigned long counter = hpet_readl(HPET_COUNTER) - vxtime.last; |
101 | return (min(counter,hpet_tick) * vxtime.quot) >> 32; | 108 | return (min(counter,hpet_tick) * vxtime.quot) >> US_SCALE; |
102 | } | 109 | } |
103 | 110 | ||
104 | unsigned int (*do_gettimeoffset)(void) = do_gettimeoffset_tsc; | 111 | unsigned int (*do_gettimeoffset)(void) = do_gettimeoffset_tsc; |
@@ -118,7 +125,7 @@ void do_gettimeofday(struct timeval *tv) | |||
118 | seq = read_seqbegin(&xtime_lock); | 125 | seq = read_seqbegin(&xtime_lock); |
119 | 126 | ||
120 | sec = xtime.tv_sec; | 127 | sec = xtime.tv_sec; |
121 | usec = xtime.tv_nsec / 1000; | 128 | usec = xtime.tv_nsec / NSEC_PER_USEC; |
122 | 129 | ||
123 | /* i386 does some correction here to keep the clock | 130 | /* i386 does some correction here to keep the clock |
124 | monotonous even when ntpd is fixing drift. | 131 | monotonous even when ntpd is fixing drift. |
@@ -129,14 +136,14 @@ void do_gettimeofday(struct timeval *tv) | |||
129 | in arch/x86_64/kernel/vsyscall.c and export all needed | 136 | in arch/x86_64/kernel/vsyscall.c and export all needed |
130 | variables in vmlinux.lds. -AK */ | 137 | variables in vmlinux.lds. -AK */ |
131 | 138 | ||
132 | t = (jiffies - wall_jiffies) * (1000000L / HZ) + | 139 | t = (jiffies - wall_jiffies) * USEC_PER_TICK + |
133 | do_gettimeoffset(); | 140 | do_gettimeoffset(); |
134 | usec += t; | 141 | usec += t; |
135 | 142 | ||
136 | } while (read_seqretry(&xtime_lock, seq)); | 143 | } while (read_seqretry(&xtime_lock, seq)); |
137 | 144 | ||
138 | tv->tv_sec = sec + usec / 1000000; | 145 | tv->tv_sec = sec + usec / USEC_PER_SEC; |
139 | tv->tv_usec = usec % 1000000; | 146 | tv->tv_usec = usec % USEC_PER_SEC; |
140 | } | 147 | } |
141 | 148 | ||
142 | EXPORT_SYMBOL(do_gettimeofday); | 149 | EXPORT_SYMBOL(do_gettimeofday); |
@@ -157,8 +164,8 @@ int do_settimeofday(struct timespec *tv) | |||
157 | 164 | ||
158 | write_seqlock_irq(&xtime_lock); | 165 | write_seqlock_irq(&xtime_lock); |
159 | 166 | ||
160 | nsec -= do_gettimeoffset() * 1000 + | 167 | nsec -= do_gettimeoffset() * NSEC_PER_USEC + |
161 | (jiffies - wall_jiffies) * (NSEC_PER_SEC/HZ); | 168 | (jiffies - wall_jiffies) * NSEC_PER_TICK; |
162 | 169 | ||
163 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); | 170 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); |
164 | wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); | 171 | wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); |
@@ -288,7 +295,7 @@ unsigned long long monotonic_clock(void) | |||
288 | this_offset = hpet_readl(HPET_COUNTER); | 295 | this_offset = hpet_readl(HPET_COUNTER); |
289 | } while (read_seqretry(&xtime_lock, seq)); | 296 | } while (read_seqretry(&xtime_lock, seq)); |
290 | offset = (this_offset - last_offset); | 297 | offset = (this_offset - last_offset); |
291 | offset *= (NSEC_PER_SEC/HZ) / hpet_tick; | 298 | offset *= NSEC_PER_TICK / hpet_tick; |
292 | } else { | 299 | } else { |
293 | do { | 300 | do { |
294 | seq = read_seqbegin(&xtime_lock); | 301 | seq = read_seqbegin(&xtime_lock); |
@@ -297,7 +304,8 @@ unsigned long long monotonic_clock(void) | |||
297 | base = monotonic_base; | 304 | base = monotonic_base; |
298 | } while (read_seqretry(&xtime_lock, seq)); | 305 | } while (read_seqretry(&xtime_lock, seq)); |
299 | this_offset = get_cycles_sync(); | 306 | this_offset = get_cycles_sync(); |
300 | offset = (this_offset - last_offset)*1000 / cpu_khz; | 307 | /* FIXME: 1000 or 1000000? */ |
308 | offset = (this_offset - last_offset)*1000 / cpu_khz; | ||
301 | } | 309 | } |
302 | return base + offset; | 310 | return base + offset; |
303 | } | 311 | } |
@@ -382,7 +390,7 @@ void main_timer_handler(struct pt_regs *regs) | |||
382 | } | 390 | } |
383 | 391 | ||
384 | monotonic_base += | 392 | monotonic_base += |
385 | (offset - vxtime.last)*(NSEC_PER_SEC/HZ) / hpet_tick; | 393 | (offset - vxtime.last) * NSEC_PER_TICK / hpet_tick; |
386 | 394 | ||
387 | vxtime.last = offset; | 395 | vxtime.last = offset; |
388 | #ifdef CONFIG_X86_PM_TIMER | 396 | #ifdef CONFIG_X86_PM_TIMER |
@@ -391,24 +399,25 @@ void main_timer_handler(struct pt_regs *regs) | |||
391 | #endif | 399 | #endif |
392 | } else { | 400 | } else { |
393 | offset = (((tsc - vxtime.last_tsc) * | 401 | offset = (((tsc - vxtime.last_tsc) * |
394 | vxtime.tsc_quot) >> 32) - (USEC_PER_SEC / HZ); | 402 | vxtime.tsc_quot) >> US_SCALE) - USEC_PER_TICK; |
395 | 403 | ||
396 | if (offset < 0) | 404 | if (offset < 0) |
397 | offset = 0; | 405 | offset = 0; |
398 | 406 | ||
399 | if (offset > (USEC_PER_SEC / HZ)) { | 407 | if (offset > USEC_PER_TICK) { |
400 | lost = offset / (USEC_PER_SEC / HZ); | 408 | lost = offset / USEC_PER_TICK; |
401 | offset %= (USEC_PER_SEC / HZ); | 409 | offset %= USEC_PER_TICK; |
402 | } | 410 | } |
403 | 411 | ||
404 | monotonic_base += (tsc - vxtime.last_tsc)*1000000/cpu_khz ; | 412 | /* FIXME: 1000 or 1000000? */ |
413 | monotonic_base += (tsc - vxtime.last_tsc) * 1000000 / cpu_khz; | ||
405 | 414 | ||
406 | vxtime.last_tsc = tsc - vxtime.quot * delay / vxtime.tsc_quot; | 415 | vxtime.last_tsc = tsc - vxtime.quot * delay / vxtime.tsc_quot; |
407 | 416 | ||
408 | if ((((tsc - vxtime.last_tsc) * | 417 | if ((((tsc - vxtime.last_tsc) * |
409 | vxtime.tsc_quot) >> 32) < offset) | 418 | vxtime.tsc_quot) >> US_SCALE) < offset) |
410 | vxtime.last_tsc = tsc - | 419 | vxtime.last_tsc = tsc - |
411 | (((long) offset << 32) / vxtime.tsc_quot) - 1; | 420 | (((long) offset << US_SCALE) / vxtime.tsc_quot) - 1; |
412 | } | 421 | } |
413 | 422 | ||
414 | if (lost > 0) { | 423 | if (lost > 0) { |
@@ -468,16 +477,15 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
468 | } | 477 | } |
469 | 478 | ||
470 | static unsigned int cyc2ns_scale __read_mostly; | 479 | static unsigned int cyc2ns_scale __read_mostly; |
471 | #define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */ | ||
472 | 480 | ||
473 | static inline void set_cyc2ns_scale(unsigned long cpu_khz) | 481 | static inline void set_cyc2ns_scale(unsigned long cpu_khz) |
474 | { | 482 | { |
475 | cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz; | 483 | cyc2ns_scale = (NSEC_PER_MSEC << NS_SCALE) / cpu_khz; |
476 | } | 484 | } |
477 | 485 | ||
478 | static inline unsigned long long cycles_2_ns(unsigned long long cyc) | 486 | static inline unsigned long long cycles_2_ns(unsigned long long cyc) |
479 | { | 487 | { |
480 | return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR; | 488 | return (cyc * cyc2ns_scale) >> NS_SCALE; |
481 | } | 489 | } |
482 | 490 | ||
483 | unsigned long long sched_clock(void) | 491 | unsigned long long sched_clock(void) |
@@ -490,7 +498,7 @@ unsigned long long sched_clock(void) | |||
490 | Disadvantage is a small drift between CPUs in some configurations, | 498 | Disadvantage is a small drift between CPUs in some configurations, |
491 | but that should be tolerable. */ | 499 | but that should be tolerable. */ |
492 | if (__vxtime.mode == VXTIME_HPET) | 500 | if (__vxtime.mode == VXTIME_HPET) |
493 | return (hpet_readl(HPET_COUNTER) * vxtime.quot) >> 32; | 501 | return (hpet_readl(HPET_COUNTER) * vxtime.quot) >> US_SCALE; |
494 | #endif | 502 | #endif |
495 | 503 | ||
496 | /* Could do CPU core sync here. Opteron can execute rdtsc speculatively, | 504 | /* Could do CPU core sync here. Opteron can execute rdtsc speculatively, |
@@ -633,7 +641,7 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, | |||
633 | 641 | ||
634 | cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new); | 642 | cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new); |
635 | if (!(freq->flags & CPUFREQ_CONST_LOOPS)) | 643 | if (!(freq->flags & CPUFREQ_CONST_LOOPS)) |
636 | vxtime.tsc_quot = (1000L << 32) / cpu_khz; | 644 | vxtime.tsc_quot = (USEC_PER_MSEC << US_SCALE) / cpu_khz; |
637 | } | 645 | } |
638 | 646 | ||
639 | set_cyc2ns_scale(cpu_khz_ref); | 647 | set_cyc2ns_scale(cpu_khz_ref); |
@@ -789,8 +797,8 @@ static int hpet_timer_stop_set_go(unsigned long tick) | |||
789 | if (hpet_use_timer) { | 797 | if (hpet_use_timer) { |
790 | hpet_writel(HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL | | 798 | hpet_writel(HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL | |
791 | HPET_TN_32BIT, HPET_T0_CFG); | 799 | HPET_TN_32BIT, HPET_T0_CFG); |
792 | hpet_writel(hpet_tick, HPET_T0_CMP); | 800 | hpet_writel(hpet_tick, HPET_T0_CMP); /* next interrupt */ |
793 | hpet_writel(hpet_tick, HPET_T0_CMP); /* AK: why twice? */ | 801 | hpet_writel(hpet_tick, HPET_T0_CMP); /* period */ |
794 | cfg |= HPET_CFG_LEGACY; | 802 | cfg |= HPET_CFG_LEGACY; |
795 | } | 803 | } |
796 | /* | 804 | /* |
@@ -825,8 +833,7 @@ static int hpet_init(void) | |||
825 | if (hpet_period < 100000 || hpet_period > 100000000) | 833 | if (hpet_period < 100000 || hpet_period > 100000000) |
826 | return -1; | 834 | return -1; |
827 | 835 | ||
828 | hpet_tick = (1000000000L * (USEC_PER_SEC / HZ) + hpet_period / 2) / | 836 | hpet_tick = (FSEC_PER_TICK + hpet_period / 2) / hpet_period; |
829 | hpet_period; | ||
830 | 837 | ||
831 | hpet_use_timer = (id & HPET_ID_LEGSUP); | 838 | hpet_use_timer = (id & HPET_ID_LEGSUP); |
832 | 839 | ||
@@ -890,18 +897,6 @@ void __init time_init(void) | |||
890 | char *timename; | 897 | char *timename; |
891 | char *gtod; | 898 | char *gtod; |
892 | 899 | ||
893 | #ifdef HPET_HACK_ENABLE_DANGEROUS | ||
894 | if (!vxtime.hpet_address) { | ||
895 | printk(KERN_WARNING "time.c: WARNING: Enabling HPET base " | ||
896 | "manually!\n"); | ||
897 | outl(0x800038a0, 0xcf8); | ||
898 | outl(0xff000001, 0xcfc); | ||
899 | outl(0x800038a0, 0xcf8); | ||
900 | vxtime.hpet_address = inl(0xcfc) & 0xfffffffe; | ||
901 | printk(KERN_WARNING "time.c: WARNING: Enabled HPET " | ||
902 | "at %#lx.\n", vxtime.hpet_address); | ||
903 | } | ||
904 | #endif | ||
905 | if (nohpet) | 900 | if (nohpet) |
906 | vxtime.hpet_address = 0; | 901 | vxtime.hpet_address = 0; |
907 | 902 | ||
@@ -912,7 +907,7 @@ void __init time_init(void) | |||
912 | -xtime.tv_sec, -xtime.tv_nsec); | 907 | -xtime.tv_sec, -xtime.tv_nsec); |
913 | 908 | ||
914 | if (!hpet_init()) | 909 | if (!hpet_init()) |
915 | vxtime_hz = (1000000000000000L + hpet_period / 2) / hpet_period; | 910 | vxtime_hz = (FSEC_PER_SEC + hpet_period / 2) / hpet_period; |
916 | else | 911 | else |
917 | vxtime.hpet_address = 0; | 912 | vxtime.hpet_address = 0; |
918 | 913 | ||
@@ -941,8 +936,8 @@ void __init time_init(void) | |||
941 | vxtime_hz / 1000000, vxtime_hz % 1000000, timename, gtod); | 936 | vxtime_hz / 1000000, vxtime_hz % 1000000, timename, gtod); |
942 | printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n", | 937 | printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n", |
943 | cpu_khz / 1000, cpu_khz % 1000); | 938 | cpu_khz / 1000, cpu_khz % 1000); |
944 | vxtime.quot = (1000000L << 32) / vxtime_hz; | 939 | vxtime.quot = (USEC_PER_SEC << US_SCALE) / vxtime_hz; |
945 | vxtime.tsc_quot = (1000L << 32) / cpu_khz; | 940 | vxtime.tsc_quot = (USEC_PER_MSEC << US_SCALE) / cpu_khz; |
946 | vxtime.last_tsc = get_cycles_sync(); | 941 | vxtime.last_tsc = get_cycles_sync(); |
947 | setup_irq(0, &irq0); | 942 | setup_irq(0, &irq0); |
948 | 943 | ||
@@ -956,10 +951,10 @@ void __init time_init(void) | |||
956 | __cpuinit int unsynchronized_tsc(void) | 951 | __cpuinit int unsynchronized_tsc(void) |
957 | { | 952 | { |
958 | #ifdef CONFIG_SMP | 953 | #ifdef CONFIG_SMP |
959 | if (oem_force_hpet_timer()) | 954 | if (apic_is_clustered_box()) |
960 | return 1; | 955 | return 1; |
961 | /* Intel systems are normally all synchronized. Exceptions | 956 | /* Intel systems are normally all synchronized. Exceptions |
962 | are handled in the OEM check above. */ | 957 | are handled in the check above. */ |
963 | if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) | 958 | if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) |
964 | return 0; | 959 | return 0; |
965 | #endif | 960 | #endif |