diff options
Diffstat (limited to 'arch/x86_64/kernel/time.c')
-rw-r--r-- | arch/x86_64/kernel/time.c | 64 |
1 files changed, 47 insertions, 17 deletions
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 0e3b60e1ac5b..fb8c809b4cd9 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c | |||
@@ -26,6 +26,10 @@ | |||
26 | #include <linux/sysdev.h> | 26 | #include <linux/sysdev.h> |
27 | #include <linux/bcd.h> | 27 | #include <linux/bcd.h> |
28 | #include <linux/kallsyms.h> | 28 | #include <linux/kallsyms.h> |
29 | #include <linux/acpi.h> | ||
30 | #ifdef CONFIG_ACPI | ||
31 | #include <acpi/achware.h> /* for PM timer frequency */ | ||
32 | #endif | ||
29 | #include <asm/8253pit.h> | 33 | #include <asm/8253pit.h> |
30 | #include <asm/pgtable.h> | 34 | #include <asm/pgtable.h> |
31 | #include <asm/vsyscall.h> | 35 | #include <asm/vsyscall.h> |
@@ -396,6 +400,10 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
396 | (offset - vxtime.last)*(NSEC_PER_SEC/HZ) / hpet_tick; | 400 | (offset - vxtime.last)*(NSEC_PER_SEC/HZ) / hpet_tick; |
397 | 401 | ||
398 | vxtime.last = offset; | 402 | vxtime.last = offset; |
403 | #ifdef CONFIG_X86_PM_TIMER | ||
404 | } else if (vxtime.mode == VXTIME_PMTMR) { | ||
405 | lost = pmtimer_mark_offset(); | ||
406 | #endif | ||
399 | } else { | 407 | } else { |
400 | offset = (((tsc - vxtime.last_tsc) * | 408 | offset = (((tsc - vxtime.last_tsc) * |
401 | vxtime.tsc_quot) >> 32) - (USEC_PER_SEC / HZ); | 409 | vxtime.tsc_quot) >> 32) - (USEC_PER_SEC / HZ); |
@@ -898,6 +906,13 @@ void __init time_init(void) | |||
898 | hpet_period; | 906 | hpet_period; |
899 | cpu_khz = hpet_calibrate_tsc(); | 907 | cpu_khz = hpet_calibrate_tsc(); |
900 | timename = "HPET"; | 908 | timename = "HPET"; |
909 | #ifdef CONFIG_X86_PM_TIMER | ||
910 | } else if (pmtmr_ioport) { | ||
911 | vxtime_hz = PM_TIMER_FREQUENCY; | ||
912 | timename = "PM"; | ||
913 | pit_init(); | ||
914 | cpu_khz = pit_calibrate_tsc(); | ||
915 | #endif | ||
901 | } else { | 916 | } else { |
902 | pit_init(); | 917 | pit_init(); |
903 | cpu_khz = pit_calibrate_tsc(); | 918 | cpu_khz = pit_calibrate_tsc(); |
@@ -923,35 +938,50 @@ void __init time_init(void) | |||
923 | } | 938 | } |
924 | 939 | ||
925 | /* | 940 | /* |
941 | * Make an educated guess if the TSC is trustworthy and synchronized | ||
942 | * over all CPUs. | ||
943 | */ | ||
944 | static __init int unsynchronized_tsc(void) | ||
945 | { | ||
946 | #ifdef CONFIG_SMP | ||
947 | if (oem_force_hpet_timer()) | ||
948 | return 1; | ||
949 | /* Intel systems are normally all synchronized. Exceptions | ||
950 | are handled in the OEM check above. */ | ||
951 | if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) | ||
952 | return 0; | ||
953 | /* All in a single socket - should be synchronized */ | ||
954 | if (cpus_weight(cpu_core_map[0]) == num_online_cpus()) | ||
955 | return 0; | ||
956 | #endif | ||
957 | /* Assume multi socket systems are not synchronized */ | ||
958 | return num_online_cpus() > 1; | ||
959 | } | ||
960 | |||
961 | /* | ||
926 | * Decide after all CPUs are booted what mode gettimeofday should use. | 962 | * Decide after all CPUs are booted what mode gettimeofday should use. |
927 | */ | 963 | */ |
928 | void __init time_init_gtod(void) | 964 | void __init time_init_gtod(void) |
929 | { | 965 | { |
930 | char *timetype; | 966 | char *timetype; |
931 | 967 | ||
932 | /* | 968 | if (unsynchronized_tsc()) |
933 | * AMD systems with more than one CPU don't have fully synchronized | ||
934 | * TSCs. Always use HPET gettimeofday for these, although it is slower. | ||
935 | * Intel SMP systems usually have synchronized TSCs, so use always | ||
936 | * the TSC. | ||
937 | * | ||
938 | * Exceptions: | ||
939 | * IBM Summit2 checked by oem_force_hpet_timer(). | ||
940 | * AMD dual core may also not need HPET. Check me. | ||
941 | * | ||
942 | * Can be turned off with "notsc". | ||
943 | */ | ||
944 | if (num_online_cpus() > 1 && | ||
945 | boot_cpu_data.x86_vendor == X86_VENDOR_AMD) | ||
946 | notsc = 1; | ||
947 | /* Some systems will want to disable TSC and use HPET. */ | ||
948 | if (oem_force_hpet_timer()) | ||
949 | notsc = 1; | 969 | notsc = 1; |
950 | if (vxtime.hpet_address && notsc) { | 970 | if (vxtime.hpet_address && notsc) { |
951 | timetype = "HPET"; | 971 | timetype = "HPET"; |
952 | vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick; | 972 | vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick; |
953 | vxtime.mode = VXTIME_HPET; | 973 | vxtime.mode = VXTIME_HPET; |
954 | do_gettimeoffset = do_gettimeoffset_hpet; | 974 | do_gettimeoffset = do_gettimeoffset_hpet; |
975 | #ifdef CONFIG_X86_PM_TIMER | ||
976 | /* Using PM for gettimeofday is quite slow, but we have no other | ||
977 | choice because the TSC is too unreliable on some systems. */ | ||
978 | } else if (pmtmr_ioport && !vxtime.hpet_address && notsc) { | ||
979 | timetype = "PM"; | ||
980 | do_gettimeoffset = do_gettimeoffset_pm; | ||
981 | vxtime.mode = VXTIME_PMTMR; | ||
982 | sysctl_vsyscall = 0; | ||
983 | printk(KERN_INFO "Disabling vsyscall due to use of PM timer\n"); | ||
984 | #endif | ||
955 | } else { | 985 | } else { |
956 | timetype = vxtime.hpet_address ? "HPET/TSC" : "PIT/TSC"; | 986 | timetype = vxtime.hpet_address ? "HPET/TSC" : "PIT/TSC"; |
957 | vxtime.mode = VXTIME_TSC; | 987 | vxtime.mode = VXTIME_TSC; |