diff options
| author | Robert Richter <robert.richter@amd.com> | 2010-10-25 10:28:14 -0400 | 
|---|---|---|
| committer | Robert Richter <robert.richter@amd.com> | 2010-10-25 10:29:12 -0400 | 
| commit | dbd1e66e04558a582e673bc4a9cd933ce0228d93 (patch) | |
| tree | 85f3633276282cde0a3ac558d988704eaa3e68af /arch/x86/kernel/tsc.c | |
| parent | 328b8f1ba50b708a1b3c0acd7c41ee1b356822f6 (diff) | |
| parent | 4a60cfa9457749f7987fd4f3c956dbba5a281129 (diff) | |
Merge commit 'linux-2.6/master' (early part) into oprofile/core
This branch depends on these apic patches:
      apic, x86: Use BIOS settings for IBS and MCE threshold interrupt LVT offsets
      apic, x86: Check if EILVT APIC registers are available (AMD only)
Signed-off-by: Robert Richter <robert.richter@amd.com>
Diffstat (limited to 'arch/x86/kernel/tsc.c')
| -rw-r--r-- | arch/x86/kernel/tsc.c | 66 | 
1 files changed, 8 insertions, 58 deletions
| diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 26a863a9c2a8..0c40d8b72416 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c | |||
| @@ -104,10 +104,14 @@ int __init notsc_setup(char *str) | |||
| 104 | 104 | ||
| 105 | __setup("notsc", notsc_setup); | 105 | __setup("notsc", notsc_setup); | 
| 106 | 106 | ||
| 107 | static int no_sched_irq_time; | ||
| 108 | |||
| 107 | static int __init tsc_setup(char *str) | 109 | static int __init tsc_setup(char *str) | 
| 108 | { | 110 | { | 
| 109 | if (!strcmp(str, "reliable")) | 111 | if (!strcmp(str, "reliable")) | 
| 110 | tsc_clocksource_reliable = 1; | 112 | tsc_clocksource_reliable = 1; | 
| 113 | if (!strncmp(str, "noirqtime", 9)) | ||
| 114 | no_sched_irq_time = 1; | ||
| 111 | return 1; | 115 | return 1; | 
| 112 | } | 116 | } | 
| 113 | 117 | ||
| @@ -801,6 +805,7 @@ void mark_tsc_unstable(char *reason) | |||
| 801 | if (!tsc_unstable) { | 805 | if (!tsc_unstable) { | 
| 802 | tsc_unstable = 1; | 806 | tsc_unstable = 1; | 
| 803 | sched_clock_stable = 0; | 807 | sched_clock_stable = 0; | 
| 808 | disable_sched_clock_irqtime(); | ||
| 804 | printk(KERN_INFO "Marking TSC unstable due to %s\n", reason); | 809 | printk(KERN_INFO "Marking TSC unstable due to %s\n", reason); | 
| 805 | /* Change only the rating, when not registered */ | 810 | /* Change only the rating, when not registered */ | 
| 806 | if (clocksource_tsc.mult) | 811 | if (clocksource_tsc.mult) | 
| @@ -892,60 +897,6 @@ static void __init init_tsc_clocksource(void) | |||
| 892 | clocksource_register_khz(&clocksource_tsc, tsc_khz); | 897 | clocksource_register_khz(&clocksource_tsc, tsc_khz); | 
| 893 | } | 898 | } | 
| 894 | 899 | ||
| 895 | #ifdef CONFIG_X86_64 | ||
| 896 | /* | ||
| 897 | * calibrate_cpu is used on systems with fixed rate TSCs to determine | ||
| 898 | * processor frequency | ||
| 899 | */ | ||
| 900 | #define TICK_COUNT 100000000 | ||
| 901 | static unsigned long __init calibrate_cpu(void) | ||
| 902 | { | ||
| 903 | int tsc_start, tsc_now; | ||
| 904 | int i, no_ctr_free; | ||
| 905 | unsigned long evntsel3 = 0, pmc3 = 0, pmc_now = 0; | ||
| 906 | unsigned long flags; | ||
| 907 | |||
| 908 | for (i = 0; i < 4; i++) | ||
| 909 | if (avail_to_resrv_perfctr_nmi_bit(i)) | ||
| 910 | break; | ||
| 911 | no_ctr_free = (i == 4); | ||
| 912 | if (no_ctr_free) { | ||
| 913 | WARN(1, KERN_WARNING "Warning: AMD perfctrs busy ... " | ||
| 914 | "cpu_khz value may be incorrect.\n"); | ||
| 915 | i = 3; | ||
| 916 | rdmsrl(MSR_K7_EVNTSEL3, evntsel3); | ||
| 917 | wrmsrl(MSR_K7_EVNTSEL3, 0); | ||
| 918 | rdmsrl(MSR_K7_PERFCTR3, pmc3); | ||
| 919 | } else { | ||
| 920 | reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i); | ||
| 921 | reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i); | ||
| 922 | } | ||
| 923 | local_irq_save(flags); | ||
| 924 | /* start measuring cycles, incrementing from 0 */ | ||
| 925 | wrmsrl(MSR_K7_PERFCTR0 + i, 0); | ||
| 926 | wrmsrl(MSR_K7_EVNTSEL0 + i, 1 << 22 | 3 << 16 | 0x76); | ||
| 927 | rdtscl(tsc_start); | ||
| 928 | do { | ||
| 929 | rdmsrl(MSR_K7_PERFCTR0 + i, pmc_now); | ||
| 930 | tsc_now = get_cycles(); | ||
| 931 | } while ((tsc_now - tsc_start) < TICK_COUNT); | ||
| 932 | |||
| 933 | local_irq_restore(flags); | ||
| 934 | if (no_ctr_free) { | ||
| 935 | wrmsrl(MSR_K7_EVNTSEL3, 0); | ||
| 936 | wrmsrl(MSR_K7_PERFCTR3, pmc3); | ||
| 937 | wrmsrl(MSR_K7_EVNTSEL3, evntsel3); | ||
| 938 | } else { | ||
| 939 | release_perfctr_nmi(MSR_K7_PERFCTR0 + i); | ||
| 940 | release_evntsel_nmi(MSR_K7_EVNTSEL0 + i); | ||
| 941 | } | ||
| 942 | |||
| 943 | return pmc_now * tsc_khz / (tsc_now - tsc_start); | ||
| 944 | } | ||
| 945 | #else | ||
| 946 | static inline unsigned long calibrate_cpu(void) { return cpu_khz; } | ||
| 947 | #endif | ||
| 948 | |||
| 949 | void __init tsc_init(void) | 900 | void __init tsc_init(void) | 
| 950 | { | 901 | { | 
| 951 | u64 lpj; | 902 | u64 lpj; | 
| @@ -964,10 +915,6 @@ void __init tsc_init(void) | |||
| 964 | return; | 915 | return; | 
| 965 | } | 916 | } | 
| 966 | 917 | ||
| 967 | if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) && | ||
| 968 | (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)) | ||
| 969 | cpu_khz = calibrate_cpu(); | ||
| 970 | |||
| 971 | printk("Detected %lu.%03lu MHz processor.\n", | 918 | printk("Detected %lu.%03lu MHz processor.\n", | 
| 972 | (unsigned long)cpu_khz / 1000, | 919 | (unsigned long)cpu_khz / 1000, | 
| 973 | (unsigned long)cpu_khz % 1000); | 920 | (unsigned long)cpu_khz % 1000); | 
| @@ -987,6 +934,9 @@ void __init tsc_init(void) | |||
| 987 | /* now allow native_sched_clock() to use rdtsc */ | 934 | /* now allow native_sched_clock() to use rdtsc */ | 
| 988 | tsc_disabled = 0; | 935 | tsc_disabled = 0; | 
| 989 | 936 | ||
| 937 | if (!no_sched_irq_time) | ||
| 938 | enable_sched_clock_irqtime(); | ||
| 939 | |||
| 990 | lpj = ((u64)tsc_khz * 1000); | 940 | lpj = ((u64)tsc_khz * 1000); | 
| 991 | do_div(lpj, HZ); | 941 | do_div(lpj, HZ); | 
| 992 | lpj_fine = lpj; | 942 | lpj_fine = lpj; | 
