From: Ingo Molnar Date: Mon, 6 Oct 2008 16:17:07 +0000 (+0200) Subject: Merge branches 'x86/alternatives', 'x86/cleanups', 'x86/commandline', 'x86/crashdump... X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=e496e3d645c93206faf61ff6005995ebd08cc39c;p=openwrt%2Fstaging%2Fblogic.git Merge branches 'x86/alternatives', 'x86/cleanups', 'x86/commandline', 'x86/crashdump', 'x86/debug', 'x86/defconfig', 'x86/doc', 'x86/exports', 'x86/fpu', 'x86/gart', 'x86/idle', 'x86/mm', 'x86/mtrr', 'x86/nmi-watchdog', 'x86/oprofile', 'x86/paravirt', 'x86/reboot', 'x86/sparse-fixes', 'x86/tsc', 'x86/urgent' and 'x86/vmalloc' into x86-v28-for-linus-phase1 --- e496e3d645c93206faf61ff6005995ebd08cc39c diff --cc arch/x86/Kconfig index ebfd7ff82ade,ac2fb0641a04,8e5e45a265d4,fbcb79bbafd2,ed92864d1325,ed92864d1325,962388cffa89,765ef6ae64e7,ed92864d1325,ac2fb0641a04,ed92864d1325,ed92864d1325,09f6b7fa29ac,ed92864d1325,68d91c8233f4,3d0f2b6a5a16,68d91c8233f4,ed92864d1325,ed92864d1325,ed92864d1325,68d91c8233f4..97f0d2b6dc0c --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@@@@@@@@@@@@@@@@@@@@@ -587,11 -585,17 -586,11 -585,17 -586,11 -586,11 -586,11 -585,17 -586,11 -585,17 -586,11 -586,11 -586,11 -586,11 -585,17 -586,17 -585,17 -586,11 -586,11 -586,11 -585,17 +587,11 @@@@@@@@@@@@@@@@@@@@@@ config MAXSM Configure maximum number of CPUS and NUMA Nodes for this architecture. If unsure, say N. - - - - --- -if MAXSMP - config NR_CPUS - int - default "4096" - endif - - if !MAXSMP config NR_CPUS - - - --- - int - - - --- - default "4096" - - - --- -endif - - - --- - - - - --- -if !MAXSMP - - - --- -config NR_CPUS - - - - --- - int "Maximum number of CPUs (2-4096)" - - - - --- - range 2 4096 + + + + +++ + int "Maximum number of CPUs (2-512)" if !MAXSMP + + + + +++ + range 2 512 depends on SMP + + + + +++ + default "4096" if MAXSMP default "32" if X86_NUMAQ || X86_SUMMIT || X86_BIGSMP || X86_ES7000 default "8" help @@@@@@@@@@@@@@@@@@@@@@ -1118,10 -1131,10 -1117,10 -1131,10 -1117,10 -1117,10 -1117,10 -1131,10 -1117,10 -1131,10 -1117,10 -1117,10 -1117,10 -1117,10 -1131,10 -1132,10 -1131,10 -1117,10 -1117,10 -1117,10 -1131,10 +1118,10 @@@@@@@@@@@@@@@@@@@@@@ config MTR You can safely say Y even if your machine doesn't have MTRRs, you'll just add about 9 KB to your kernel. ------- ------------- See for more information. +++++++ +++++++++++++ See for more information. config MTRR_SANITIZER ------------ -------- bool ++++++++++++ ++++++++ def_bool y prompt "MTRR cleanup support" depends on MTRR help diff --cc arch/x86/kernel/cpu/mtrr/main.c index 5df16d818371,6f23969c8faf,8a7c79234be6,6f23969c8faf,b117d7f8a564,b117d7f8a564,b117d7f8a564,6f23969c8faf,b117d7f8a564,6f23969c8faf,b117d7f8a564,b117d7f8a564,5994a9f78f3d,b117d7f8a564,6f23969c8faf,6f23969c8faf,b117d7f8a564,b117d7f8a564,b117d7f8a564,885c8265e6b5,6f23969c8faf..c78c04821ea1 --- a/arch/x86/kernel/cpu/mtrr/main.c +++ b/arch/x86/kernel/cpu/mtrr/main.c @@@@@@@@@@@@@@@@@@@@@@ -834,8 -834,8 -834,8 -834,8 -834,8 -834,8 -834,8 -834,8 -834,8 -834,8 -834,8 -834,8 -835,15 -834,8 -834,8 -834,8 -834,8 -834,8 -834,8 -834,8 -834,8 +835,15 @@@@@@@@@@@@@@@@@@@@@@ static int __init enable_mtrr_cleanup_s enable_mtrr_cleanup = 1; return 0; } ------------------ -early_param("enble_mtrr_cleanup", enable_mtrr_cleanup_setup); ++++++++++++++++++ +early_param("enable_mtrr_cleanup", enable_mtrr_cleanup_setup); +++++++++++ ++++++ + ++++++++++++ ++++++++static int __init mtrr_cleanup_debug_setup(char *str) ++++++++++++ ++++++++{ ++++++++++++ ++++++++ debug_print = 1; ++++++++++++ ++++++++ return 0; ++++++++++++ ++++++++} ++++++++++++ ++++++++early_param("mtrr_cleanup_debug", mtrr_cleanup_debug_setup); + + struct var_mtrr_state { unsigned long range_startk; unsigned long range_sizek; @@@@@@@@@@@@@@@@@@@@@@ -996,50 -996,50 -996,50 -996,50 -996,50 -996,50 -996,50 -996,50 -996,50 -996,50 -996,50 -996,50 -1062,28 -996,50 -996,50 -996,50 -996,50 -996,50 -996,50 -996,50 -996,50 +1062,28 @@@@@@@@@@@@@@@@@@@@@@ second_try (range0_basek + range0_sizek)<<10); state->reg = range_to_mtrr(state->reg, range0_basek, range0_sizek, MTRR_TYPE_WRBACK); - --- - -- - ---- - --- - -- - ---- } - --- - -- - ---- - --- - -- - ---- range_basek = range0_basek + range0_sizek; - --- - -- - ---- range_sizek = chunk_sizek; ------------ -------- - --- - -- - ---- if (range_basek + range_sizek > basek && - --- - -- - ---- range_basek + range_sizek <= (basek + sizek)) { - --- - -- - ---- /* one hole */ - --- - -- - ---- second_basek = basek; - --- - -- - ---- second_sizek = range_basek + range_sizek - basek; } --- - - -- - range_basek = range0_basek + range0_sizek; --- - - -- - range_sizek = chunk_sizek; --- - - -- - --- - - -- - if (range_basek + range_sizek > basek && --- - - -- - range_basek + range_sizek <= (basek + sizek)) { --- - - -- - /* one hole */ --- - - -- - second_basek = basek; --- - - -- - second_sizek = range_basek + range_sizek - basek; --- - - -- - } --- - - -- - ------------ -------- /* if last piece, only could one hole near end */ ------------ -------- if ((second_basek || !basek) && ------------ -------- range_sizek - (state->range_sizek - range0_sizek) - second_sizek < ------------ -------- (chunk_sizek >> 1)) { ------------ -------- /* ------------ -------- * one hole in middle (second_sizek is 0) or at end ------------ -------- * (second_sizek is 0 ) ------------ -------- */ ------------ -------- hole_sizek = range_sizek - (state->range_sizek - range0_sizek) ------------ -------- - second_sizek; ------------ -------- hole_basek = range_basek + range_sizek - hole_sizek ------------ -------- - second_sizek; ------------ -------- } else { ------------ -------- /* fallback for big hole, or several holes */ ++++++++++++ ++++++++ if (range0_sizek < state->range_sizek) { ++++++++++++ ++++++++ /* need to handle left over */ range_sizek = state->range_sizek - range0_sizek; ------------ -------- second_basek = 0; ------------ -------- second_sizek = 0; ++++++++++++ ++++++++ ++++++++++++ ++++++++ if (debug_print) ++++++++++++ ++++++++ printk(KERN_DEBUG "range: %016lx - %016lx\n", ++++++++++++ ++++++++ range_basek<<10, ++++++++++++ ++++++++ (range_basek + range_sizek)<<10); ++++++++++++ ++++++++ state->reg = range_to_mtrr(state->reg, range_basek, ++++++++++++ ++++++++ range_sizek, MTRR_TYPE_WRBACK); } ------------ -------- if (debug_print) ------------ -------- printk(KERN_DEBUG "range: %016lx - %016lx\n", range_basek<<10, ------------ -------- (range_basek + range_sizek)<<10); ------------ -------- state->reg = range_to_mtrr(state->reg, range_basek, range_sizek, ------------ -------- MTRR_TYPE_WRBACK); if (hole_sizek) { ++++++++++++ ++++++++ hole_basek = range_basek - hole_sizek - second_sizek; if (debug_print) printk(KERN_DEBUG "hole: %016lx - %016lx\n", ------------ -------- hole_basek<<10, (hole_basek + hole_sizek)<<10); ------------ -------- state->reg = range_to_mtrr(state->reg, hole_basek, hole_sizek, ------------ -------- MTRR_TYPE_UNCACHABLE); ------------ -------- ++++++++++++ ++++++++ hole_basek<<10, ++++++++++++ ++++++++ (hole_basek + hole_sizek)<<10); ++++++++++++ ++++++++ state->reg = range_to_mtrr(state->reg, hole_basek, ++++++++++++ ++++++++ hole_sizek, MTRR_TYPE_UNCACHABLE); } return second_sizek; @@@@@@@@@@@@@@@@@@@@@@ -1216,15 -1216,15 -1216,14 -1216,15 -1216,15 -1216,15 -1216,15 -1216,15 -1216,15 -1216,15 -1216,15 -1216,15 -1263,48 -1216,15 -1216,15 -1216,15 -1216,15 -1216,15 -1216,15 -1216,15 -1216,15 +1263,47 @@@@@@@@@@@@@@@@@@@@@@ static int __init mtrr_cleanup(unsigne num_var_ranges - num[MTRR_NUM_TYPES]) return 0; ++++++++++++ ++++++++ /* print original var MTRRs at first, for debugging: */ ++++++++++++ ++++++++ printk(KERN_DEBUG "original variable MTRRs\n"); ++++++++++++ ++++++++ for (i = 0; i < num_var_ranges; i++) { ++++++++++++ ++++++++ char start_factor = 'K', size_factor = 'K'; ++++++++++++ ++++++++ unsigned long start_base, size_base; ++++++++++++ ++++++++ ++++++++++++ ++++++++ size_base = range_state[i].size_pfn << (PAGE_SHIFT - 10); ++++++++++++ ++++++++ if (!size_base) ++++++++++++ ++++++++ continue; ++++++++++++ ++++++++ ++++++++++++ ++++++++ size_base = to_size_factor(size_base, &size_factor), ++++++++++++ ++++++++ start_base = range_state[i].base_pfn << (PAGE_SHIFT - 10); ++++++++++++ ++++++++ start_base = to_size_factor(start_base, &start_factor), ++++++++++++ ++++++++ type = range_state[i].type; ++++++++++++ ++++++++ ++++++++++++ ++++++++ printk(KERN_DEBUG "reg %d, base: %ld%cB, range: %ld%cB, type %s\n", ++++++++++++ ++++++++ i, start_base, start_factor, ++++++++++++ ++++++++ size_base, size_factor, ++++++++++++ ++++++++ (type == MTRR_TYPE_UNCACHABLE) ? "UC" : ++++++++++++ ++++++++ ((type == MTRR_TYPE_WRPROT) ? "WP" : ++++++++++++ ++++++++ ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other")) ++++++++++++ ++++++++ ); ++++++++++++ ++++++++ } ++++++++++++ ++++++++ memset(range, 0, sizeof(range)); extra_remove_size = 0; -- ------------------ if (mtrr_tom2) { -- ------------------ extra_remove_base = 1 << (32 - PAGE_SHIFT); ++ ++++++++++++++++++ extra_remove_base = 1 << (32 - PAGE_SHIFT); ++ ++++++++++++++++++ if (mtrr_tom2) extra_remove_size = (mtrr_tom2 >> PAGE_SHIFT) - extra_remove_base; -- ------------------ } nr_range = x86_get_mtrr_mem_range(range, 0, extra_remove_base, extra_remove_size); ++++++++++++ ++++++++ /* ++++++++++++ ++++++++ * [0, 1M) should always be coverred by var mtrr with WB ++++++++++++ ++++++++ * and fixed mtrrs should take effective before var mtrr for it ++++++++++++ ++++++++ */ ++++++++++++ ++++++++ nr_range = add_range_with_merge(range, nr_range, 0, ++++++++++++ ++++++++ (1ULL<<(20 - PAGE_SHIFT)) - 1); ++++++++++++ ++++++++ /* sort the ranges */ ++++++++++++ ++++++++ sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL); ++++++++++++ ++++++++ range_sums = sum_ranges(range, nr_range); printk(KERN_INFO "total RAM coverred: %ldM\n", range_sums >> (20 - PAGE_SHIFT)); diff --cc arch/x86/kernel/process_32.c index c8609dea443f,53bc653ed5ca,3b7a1ddcc0bc,53bc653ed5ca,3b7a1ddcc0bc,62a4790e425d,3b7a1ddcc0bc,3b7a1ddcc0bc,31f40b24bf5d,53bc653ed5ca,3b7a1ddcc0bc,3b7a1ddcc0bc,31f40b24bf5d,3b7a1ddcc0bc,3b7a1ddcc0bc,53bc653ed5ca,3b7a1ddcc0bc,4b3cfdf54216,3b7a1ddcc0bc,31f40b24bf5d,3b7a1ddcc0bc..205188db9626 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@@@@@@@@@@@@@@@@@@@@@ -55,9 -55,6 -55,6 -55,6 -55,6 -56,6 -55,6 -55,6 -55,7 -55,6 -55,6 -55,6 -55,7 -55,6 -55,6 -55,6 -55,6 -55,6 -55,6 -55,7 -55,6 +56,9 @@@@@@@@@@@@@@@@@@@@@@ #include #include #include +++++++ +++ ++++++ +#include ++++++++++++++++++++#include ++++++++++++++++++++#include asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); diff --cc arch/x86/kernel/process_64.c index 79e3e173ab40,3fb62a7d9a16,e04134a80c22,3fb62a7d9a16,71553b664e2a,71553b664e2a,71553b664e2a,71553b664e2a,e12e0e4dd256,3fb62a7d9a16,71553b664e2a,71553b664e2a,e12e0e4dd256,71553b664e2a,71553b664e2a,3fb62a7d9a16,71553b664e2a,e12e0e4dd256,71553b664e2a,e12e0e4dd256,71553b664e2a..2a8ccb9238b4 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@@@@@@@@@@@@@@@@@@@@@ -94,8 -93,7 -93,6 -93,7 -93,6 -93,6 -93,6 -93,6 -93,8 -93,7 -93,6 -93,6 -93,8 -93,6 -93,6 -93,7 -93,6 -93,8 -93,6 -93,8 -93,6 +94,8 @@@@@@@@@@@@@@@@@@@@@@ DECLARE_PER_CPU(int, cpu_state) static inline void play_dead(void) { idle_task_exit(); - - - - wbinvd(); +++++++ +++ ++++ + + c1e_remove_cpu(raw_smp_processor_id()); +++++++ +++ ++++ + + mb(); /* Ack it */ __get_cpu_var(cpu_state) = CPU_DEAD; diff --cc arch/x86/kernel/setup.c index 9838f2539dfc,68b48e3fbcbd,362d4e7f2d38,2f31cddd27b7,9838f2539dfc,9838f2539dfc,362d4e7f2d38,a4656adab53b,9838f2539dfc,68b48e3fbcbd,362d4e7f2d38,362d4e7f2d38,9838f2539dfc,9838f2539dfc,a4656adab53b,b520dae02bf4,362d4e7f2d38,9838f2539dfc,362d4e7f2d38,9838f2539dfc,a4656adab53b..141efab52400 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@@@@@@@@@@@@@@@@@@@@@ -670,18 -678,6 -670,14 -694,6 -670,18 -670,18 -670,14 -678,6 -670,18 -678,6 -670,14 -670,14 -670,18 -670,18 -678,6 -670,6 -670,14 -670,18 -670,14 -670,18 -678,6 +686,18 @@@@@@@@@@@@@@@@@@@@@@ void __init setup_arch(char **cmdline_p parse_early_param(); +++ ++ +++ +++ + +#ifdef CONFIG_X86_64 +++ ++ +++ +++ + + check_efer(); +++ ++ +++ +++ + +#endif +++ ++ +++ +++ + + + + + + ++ +#if defined(CONFIG_VMI) && defined(CONFIG_X86_32) + + + + ++ + /* + + + + ++ + * Must be before kernel pagetables are setup + + + + ++ + * or fixmap area is touched. + + + + ++ + */ + + + + ++ + vmi_init(); + + + + ++ +#endif + + + + ++ + /* after early param, so could get panic from serial */ reserve_early_setup_data(); diff --cc arch/x86/kernel/signal_64.c index 4d32487805ef,b45ef8ddd651,162da796a323,b45ef8ddd651,ca316b5b742c,ca316b5b742c,ca316b5b742c,ca316b5b742c,ca316b5b742c,b45ef8ddd651,ca316b5b742c,ca316b5b742c,ca316b5b742c,ca316b5b742c,ca316b5b742c,b45ef8ddd651,ca316b5b742c,ca316b5b742c,ca316b5b742c,ca316b5b742c,ca316b5b742c..694aa888bb19 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c @@@@@@@@@@@@@@@@@@@@@@ -357,9 -345,38 -351,38 -345,38 -354,38 -354,38 -354,38 -354,38 -354,38 -345,38 -354,38 -354,38 -354,38 -354,38 -354,38 -345,38 -354,38 -354,38 -354,38 -354,38 -354,38 +354,9 @@@@@@@@@@@@@@@@@@@@@@ give_sigsegv return -EFAULT; } --------------------/* -------------------- * Return -1L or the syscall number that @regs is executing. -------------------- */ --------------------static long current_syscall(struct pt_regs *regs) --------------------{ -------------------- /* -------------------- * We always sign-extend a -1 value being set here, -------------------- * so this is always either -1L or a syscall number. -------------------- */ -------------------- return regs->orig_ax; --------------------} -------------------- --------------------/* -------------------- * Return a value that is -EFOO if the system call in @regs->orig_ax -------------------- * returned an error. This only works for @regs from @current. -------------------- */ --------------------static long current_syscall_ret(struct pt_regs *regs) --------------------{ --------------------#ifdef CONFIG_IA32_EMULATION -------------------- if (test_thread_flag(TIF_IA32)) -------------------- /* -------------------- * Sign-extend the value so (int)-EFOO becomes (long)-EFOO -------------------- * and will match correctly in comparisons. -------------------- */ -------------------- return (int) regs->ax; --------------------#endif -------------------- return regs->ax; --------------------} -------------------- /* * OK, we're invoking a handler -- ------------------ */ ++ ++++++++++++++++++ */ static int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, @@@@@@@@@@@@@@@@@@@@@@ -427,16 -444,15 -450,15 -444,15 -453,15 -453,15 -453,15 -453,15 -453,15 -444,15 -453,15 -453,15 -453,15 -453,15 -453,15 -444,15 -453,15 -453,15 -453,15 -453,15 -453,15 +424,16 @@@@@@@@@@@@@@@@@@@@@@ * handler too. */ regs->flags &= ~X86_EFLAGS_TF; -------------------- if (test_thread_flag(TIF_SINGLESTEP)) -------------------- ptrace_notify(SIGTRAP); spin_lock_irq(¤t->sighand->siglock); -- ------------------ sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); ++ ++++++++++++++++++ sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); if (!(ka->sa.sa_flags & SA_NODEFER)) -- ------------------ sigaddset(¤t->blocked,sig); ++ ++++++++++++++++++ sigaddset(¤t->blocked, sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); ++++++++++++++++++++ ++++++++++++++++++++ tracehook_signal_handler(sig, info, ka, regs, ++++++++++++++++++++ test_thread_flag(TIF_SINGLESTEP)); } return ret; diff --cc arch/x86/kernel/sys_x86_64.c index c9288c883e20,3b360ef33817,56eb8f916e9f,3b360ef33817,3b360ef33817,3b360ef33817,3b360ef33817,3b360ef33817,3b360ef33817,3b360ef33817,3b360ef33817,3b360ef33817,3b360ef33817,3b360ef33817,3b360ef33817,3b360ef33817,3b360ef33817,3b360ef33817,3b360ef33817,3b360ef33817,3b360ef33817..6bc211accf08 --- a/arch/x86/kernel/sys_x86_64.c +++ b/arch/x86/kernel/sys_x86_64.c @@@@@@@@@@@@@@@@@@@@@@ -13,16 -13,15 -13,16 -13,15 -13,15 -13,15 -13,15 -13,15 -13,15 -13,15 -13,15 -13,15 -13,15 -13,15 -13,15 -13,15 -13,15 -13,15 -13,15 -13,15 -13,15 +13,17 @@@@@@@@@@@@@@@@@@@@@@ #include #include #include ++ ++++++++++++++++++#include -- ------------------#include #include ++++++++++++++++++++#include -- ------------------asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, -- ------------------ unsigned long fd, unsigned long off) ++ ++++++++++++++++++asmlinkage long sys_mmap(unsigned long addr, unsigned long len, ++ ++++++++++++++++++ unsigned long prot, unsigned long flags, ++ ++++++++++++++++++ unsigned long fd, unsigned long off) { long error; -- ------------------ struct file * file; ++ ++++++++++++++++++ struct file *file; error = -EINVAL; if (off & ~PAGE_MASK) diff --cc arch/x86/kernel/tsc.c index 8f98e9de1b82,7603c0553909,8f98e9de1b82,7603c0553909,8f98e9de1b82,8f98e9de1b82,8f98e9de1b82,46af71676738,8f98e9de1b82,7603c0553909,8e786b0d665a,8f98e9de1b82,8f98e9de1b82,8f98e9de1b82,46af71676738,7603c0553909,46af71676738,8f98e9de1b82,4847a9280505,8f98e9de1b82,46af71676738..161bb850fc47 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@@@@@@@@@@@@@@@@@@@@@ -104,7 -104,7 -104,7 -104,7 -104,7 -104,7 -104,7 -104,7 -104,7 -104,7 -104,7 -104,7 -104,7 -104,7 -104,7 -104,7 -104,7 -104,7 -104,7 -104,7 -104,7 +104,7 @@@@@@@@@@@@@@@@@@@@@@ __setup("notsc", notsc_setup) /* * Read TSC and the reference counters. Take care of SMI disturbance */ - - ----- ----- -- --static u64 tsc_read_refs(u64 *pm, u64 *hpet) - - - - static u64 __init tsc_read_refs(u64 *pm, u64 *hpet) ++++++++++++++++++ ++static u64 tsc_read_refs(u64 *p, int hpet) { u64 t1, t2; int i; @@@@@@@@@@@@@@@@@@@@@@ -122,216 -122,80 -122,216 -122,80 -122,216 -122,216 -122,216 -122,80 -122,216 -122,80 -122,80 -122,216 -122,216 -122,216 -122,80 -122,80 -122,80 -122,216 -122,391 -122,216 -122,80 +122,390 @@@@@@@@@@@@@@@@@@@@@@ return ULLONG_MAX; } - - - -- --- -/** - - - -- --- - * native_calibrate_tsc - calibrate the tsc on boot ++++++++++++++++++ ++/* ++++++++++++++++++ ++ * Calculate the TSC frequency from HPET reference + + +++ + +++ + + */ - - - -- --- -unsigned long native_calibrate_tsc(void) ++++++++++++++++++ ++static unsigned long calc_hpet_ref(u64 deltatsc, u64 hpet1, u64 hpet2) + + +++ + +++ + + { - - - -- --- - unsigned long flags; - - - -- --- - u64 tsc1, tsc2, tr1, tr2, delta, pm1, pm2, hpet1, hpet2; - - - -- --- - int hpet = is_hpet_enabled(); - - - -- --- - unsigned int tsc_khz_val = 0; ++++++++++++++++++ ++ u64 tmp; + + +++ + +++ + + - - - -- --- - local_irq_save(flags); ++++++++++++++++++ ++ if (hpet2 < hpet1) ++++++++++++++++++ ++ hpet2 += 0x100000000ULL; ++++++++++++++++++ ++ hpet2 -= hpet1; ++++++++++++++++++ ++ tmp = ((u64)hpet2 * hpet_readl(HPET_PERIOD)); ++++++++++++++++++ ++ do_div(tmp, 1000000); ++++++++++++++++++ ++ do_div(deltatsc, tmp); ++++++++++++++++++ ++ ++++++++++++++++++ ++ return (unsigned long) deltatsc; ++++++++++++++++++ ++} ++++++++++++++++++ ++ ++++++++++++++++++ ++/* ++++++++++++++++++ ++ * Calculate the TSC frequency from PMTimer reference ++++++++++++++++++ ++ */ ++++++++++++++++++ ++static unsigned long calc_pmtimer_ref(u64 deltatsc, u64 pm1, u64 pm2) ++++++++++++++++++ ++{ ++++++++++++++++++ ++ u64 tmp; + + +++ + ++++ + + - - - - --- - tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL); ++++++++++++++++++ ++ if (!pm1 && !pm2) ++++++++++++++++++ ++ return ULONG_MAX; ++++++++++++++++++ ++ ++++++++++++++++++ ++ if (pm2 < pm1) ++++++++++++++++++ ++ pm2 += (u64)ACPI_PM_OVRRUN; ++++++++++++++++++ ++ pm2 -= pm1; ++++++++++++++++++ ++ tmp = pm2 * 1000000000LL; ++++++++++++++++++ ++ do_div(tmp, PMTMR_TICKS_PER_SEC); ++++++++++++++++++ ++ do_div(deltatsc, tmp); ++++++++++++++++++ ++ ++++++++++++++++++ ++ return (unsigned long) deltatsc; ++++++++++++++++++ ++} ++++++++++++++++++ ++ ++++++++++++++++++ ++#define CAL_MS 10 ++++++++++++++++++ ++#define CAL_LATCH (CLOCK_TICK_RATE / (1000 / CAL_MS)) ++++++++++++++++++ ++#define CAL_PIT_LOOPS 1000 ++++++++++++++++++ ++ ++++++++++++++++++ ++#define CAL2_MS 50 ++++++++++++++++++ ++#define CAL2_LATCH (CLOCK_TICK_RATE / (1000 / CAL2_MS)) ++++++++++++++++++ ++#define CAL2_PIT_LOOPS 5000 ++++++++++++++++++ ++ ++++++++++++++++++ ++ + + + ++ +++ +/* + + + ++ +++ + * Try to calibrate the TSC against the Programmable + + + ++ +++ + * Interrupt Timer and return the frequency of the TSC + + + ++ +++ + * in kHz. + + + ++ +++ + * + + + ++ +++ + * Return ULONG_MAX on failure to calibrate. + + + ++ +++ + */ - - --- - --- - - static unsigned long pit_calibrate_tsc(void) ++++++++++++++++++ ++static unsigned long pit_calibrate_tsc(u32 latch, unsigned long ms, int loopmin) + + + ++ +++ +{ + + + ++ +++ + u64 tsc, t1, t2, delta; + + + ++ +++ + unsigned long tscmin, tscmax; + + + ++ +++ + int pitcnt; + + + + ++ +++ + /* Set the Gate high, disable speaker */ + outb((inb(0x61) & ~0x02) | 0x01, 0x61); + + + + ++ +++ + /* + + + ++ +++ + * Setup CTC channel 2* for mode 0, (interrupt on terminal + + + ++ +++ + * count mode), binary count. Set the latch register to 50ms + + + ++ +++ + * (LSB then MSB) to begin countdown. + + + ++ +++ + */ + outb(0xb0, 0x43); ---------- ------- -- outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42); ---------- ------- -- outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42); - - - - --- - tr1 = get_cycles(); - - - - --- - while ((inb(0x61) & 0x20) == 0); - - - - --- - tr2 = get_cycles(); ++++++++++++++++++ ++ outb(latch & 0xff, 0x42); ++++++++++++++++++ ++ outb(latch >> 8, 0x42); + - - - - --- - tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL); + + + ++ +++ + tsc = t1 = t2 = get_cycles(); + + + ++ +++ + + + + ++ +++ + pitcnt = 0; + + + ++ +++ + tscmax = 0; + + + ++ +++ + tscmin = ULONG_MAX; + + + ++ +++ + while ((inb(0x61) & 0x20) == 0) { + + + ++ +++ + t2 = get_cycles(); + + + ++ +++ + delta = t2 - tsc; + + + ++ +++ + tsc = t2; + + + ++ +++ + if ((unsigned long) delta < tscmin) + + + ++ +++ + tscmin = (unsigned int) delta; + + + ++ +++ + if ((unsigned long) delta > tscmax) + + + ++ +++ + tscmax = (unsigned int) delta; + + + ++ +++ + pitcnt++; + + + ++ +++ + } + + + ++ +++ + + + + ++ +++ + /* + + + ++ +++ + * Sanity checks: + + + ++ +++ + * - - --- - --- - - * If we were not able to read the PIT more than 5000 ++++++++++++++++++ ++ * If we were not able to read the PIT more than loopmin + + + ++ +++ + * times, then we have been hit by a massive SMI + + + ++ +++ + * + + + ++ +++ + * If the maximum is 10 times larger than the minimum, + + + ++ +++ + * then we got hit by an SMI as well. + + + ++ +++ + */ - - --- - --- - - if (pitcnt < 5000 || tscmax > 10 * tscmin) ++++++++++++++++++ ++ if (pitcnt < loopmin || tscmax > 10 * tscmin) + + + ++ +++ + return ULONG_MAX; + + + ++ +++ + + + + ++ +++ + /* Calculate the PIT value */ + + + ++ +++ + delta = t2 - t1; - - --- - --- - - do_div(delta, 50); ++++++++++++++++++ ++ do_div(delta, ms); + + + ++ +++ + return delta; + + + ++ +++ +} + ++++++++++++++++++ ++/* ++++++++++++++++++ ++ * This reads the current MSB of the PIT counter, and ++++++++++++++++++ ++ * checks if we are running on sufficiently fast and ++++++++++++++++++ ++ * non-virtualized hardware. ++++++++++++++++++ ++ * ++++++++++++++++++ ++ * Our expectations are: ++++++++++++++++++ ++ * ++++++++++++++++++ ++ * - the PIT is running at roughly 1.19MHz ++++++++++++++++++ ++ * ++++++++++++++++++ ++ * - each IO is going to take about 1us on real hardware, ++++++++++++++++++ ++ * but we allow it to be much faster (by a factor of 10) or ++++++++++++++++++ ++ * _slightly_ slower (ie we allow up to a 2us read+counter ++++++++++++++++++ ++ * update - anything else implies a unacceptably slow CPU ++++++++++++++++++ ++ * or PIT for the fast calibration to work. ++++++++++++++++++ ++ * ++++++++++++++++++ ++ * - with 256 PIT ticks to read the value, we have 214us to ++++++++++++++++++ ++ * see the same MSB (and overhead like doing a single TSC ++++++++++++++++++ ++ * read per MSB value etc). ++++++++++++++++++ ++ * ++++++++++++++++++ ++ * - We're doing 2 reads per loop (LSB, MSB), and we expect ++++++++++++++++++ ++ * them each to take about a microsecond on real hardware. ++++++++++++++++++ ++ * So we expect a count value of around 100. But we'll be ++++++++++++++++++ ++ * generous, and accept anything over 50. ++++++++++++++++++ ++ * ++++++++++++++++++ ++ * - if the PIT is stuck, and we see *many* more reads, we ++++++++++++++++++ ++ * return early (and the next caller of pit_expect_msb() ++++++++++++++++++ ++ * then consider it a failure when they don't see the ++++++++++++++++++ ++ * next expected value). ++++++++++++++++++ ++ * ++++++++++++++++++ ++ * These expectations mean that we know that we have seen the ++++++++++++++++++ ++ * transition from one expected value to another with a fairly ++++++++++++++++++ ++ * high accuracy, and we didn't miss any events. We can thus ++++++++++++++++++ ++ * use the TSC value at the transitions to calculate a pretty ++++++++++++++++++ ++ * good value for the TSC frequencty. ++++++++++++++++++ ++ */ ++++++++++++++++++ ++static inline int pit_expect_msb(unsigned char val) ++++++++++++++++++ ++{ ++++++++++++++++++ ++ int count = 0; ++++++++++ +++++++ ++ - tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL); ++++++++++++++++++ ++ for (count = 0; count < 50000; count++) { ++++++++++++++++++ ++ /* Ignore LSB */ ++++++++++++++++++ ++ inb(0x42); ++++++++++++++++++ ++ if (inb(0x42) != val) ++++++++++++++++++ ++ break; ++++++++++++++++++ ++ } ++++++++++++++++++ ++ return count > 50; ++++++++++++++++++ ++} ++++++++++++++++++ ++ ++++++++++++++++++ ++/* ++++++++++++++++++ ++ * How many MSB values do we want to see? We aim for a ++++++++++++++++++ ++ * 15ms calibration, which assuming a 2us counter read ++++++++++++++++++ ++ * error should give us roughly 150 ppm precision for ++++++++++++++++++ ++ * the calibration. ++++++++++++++++++ ++ */ ++++++++++++++++++ ++#define QUICK_PIT_MS 15 ++++++++++++++++++ ++#define QUICK_PIT_ITERATIONS (QUICK_PIT_MS * PIT_TICK_RATE / 1000 / 256) ++++++++++ +++++++ ++ ++++++++++++++++++ ++static unsigned long quick_pit_calibrate(void) ++++++++++++++++++ ++{ ++++++++++++++++++ ++ /* Set the Gate high, disable speaker */ ++++++++++ +++++++ ++ outb((inb(0x61) & ~0x02) | 0x01, 0x61); ++++++++++ +++++++ ++ ++++++++++++++++++ ++ /* ++++++++++++++++++ ++ * Counter 2, mode 0 (one-shot), binary count ++++++++++++++++++ ++ * ++++++++++++++++++ ++ * NOTE! Mode 2 decrements by two (and then the ++++++++++++++++++ ++ * output is flipped each time, giving the same ++++++++++++++++++ ++ * final output frequency as a decrement-by-one), ++++++++++++++++++ ++ * so mode 0 is much better when looking at the ++++++++++++++++++ ++ * individual counts. ++++++++++++++++++ ++ */ ++++++++++ +++++++ ++ outb(0xb0, 0x43); - outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42); - outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42); - tr1 = get_cycles(); - while ((inb(0x61) & 0x20) == 0); - tr2 = get_cycles(); ++++++++++ +++++++ ++ - tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL); ++++++++++++++++++ ++ /* Start at 0xffff */ ++++++++++++++++++ ++ outb(0xff, 0x42); ++++++++++++++++++ ++ outb(0xff, 0x42); ++++++++++++++++++ ++ ++++++++++++++++++ ++ if (pit_expect_msb(0xff)) { ++++++++++++++++++ ++ int i; ++++++++++++++++++ ++ u64 t1, t2, delta; ++++++++++++++++++ ++ unsigned char expect = 0xfe; ++++++++++++++++++ ++ ++++++++++++++++++ ++ t1 = get_cycles(); ++++++++++++++++++ ++ for (i = 0; i < QUICK_PIT_ITERATIONS; i++, expect--) { ++++++++++++++++++ ++ if (!pit_expect_msb(expect)) ++++++++++++++++++ ++ goto failed; ++++++++++++++++++ ++ } ++++++++++++++++++ ++ t2 = get_cycles(); ++++++++++++++++++ ++ ++++++++++++++++++ ++ /* ++++++++++++++++++ ++ * Make sure we can rely on the second TSC timestamp: ++++++++++++++++++ ++ */ ++++++++++++++++++ ++ if (!pit_expect_msb(expect)) ++++++++++++++++++ ++ goto failed; ++++++++++++++++++ ++ ++++++++++++++++++ ++ /* ++++++++++++++++++ ++ * Ok, if we get here, then we've seen the ++++++++++++++++++ ++ * MSB of the PIT decrement QUICK_PIT_ITERATIONS ++++++++++++++++++ ++ * times, and each MSB had many hits, so we never ++++++++++++++++++ ++ * had any sudden jumps. ++++++++++++++++++ ++ * ++++++++++++++++++ ++ * As a result, we can depend on there not being ++++++++++++++++++ ++ * any odd delays anywhere, and the TSC reads are ++++++++++++++++++ ++ * reliable. ++++++++++++++++++ ++ * ++++++++++++++++++ ++ * kHz = ticks / time-in-seconds / 1000; ++++++++++++++++++ ++ * kHz = (t2 - t1) / (QPI * 256 / PIT_TICK_RATE) / 1000 ++++++++++++++++++ ++ * kHz = ((t2 - t1) * PIT_TICK_RATE) / (QPI * 256 * 1000) ++++++++++++++++++ ++ */ ++++++++++++++++++ ++ delta = (t2 - t1)*PIT_TICK_RATE; ++++++++++++++++++ ++ do_div(delta, QUICK_PIT_ITERATIONS*256*1000); ++++++++++++++++++ ++ printk("Fast TSC calibration using PIT\n"); ++++++++++++++++++ ++ return delta; ++++++++++++++++++ ++ } ++++++++++++++++++ ++failed: ++++++++++++++++++ ++ return 0; ++++++++++++++++++ ++} + + + + +++ + + + + ++ +++ +/** + + + ++ +++ + * native_calibrate_tsc - calibrate the tsc on boot + + + ++ +++ + */ + + + ++ +++ +unsigned long native_calibrate_tsc(void) + + + ++ +++ +{ - - --- - --- - - u64 tsc1, tsc2, delta, pm1, pm2, hpet1, hpet2; ++++++++++++++++++ ++ u64 tsc1, tsc2, delta, ref1, ref2; + + + ++ +++ + unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX; - - --- - --- - - unsigned long flags; - - --- - --- - - int hpet = is_hpet_enabled(), i; ++++++++++++++++++ ++ unsigned long flags, latch, ms, fast_calibrate; ++++++++++++++++++ ++ int hpet = is_hpet_enabled(), i, loopmin; ++++++++++++++++++ ++ ++++++++++++++++++ ++ local_irq_save(flags); ++++++++++++++++++ ++ fast_calibrate = quick_pit_calibrate(); + + +++ + +++ + + local_irq_restore(flags); ++++++++++++++++++ ++ if (fast_calibrate) ++++++++++++++++++ ++ return fast_calibrate; /* - - - -- --- - * Preset the result with the raw and inaccurate PIT - - - -- --- - * calibration value + + + ++ +++ + * Run 5 calibration loops to get the lowest frequency value + + + ++ +++ + * (the best estimate). We use two different calibration modes + + + ++ +++ + * here: + + + ++ +++ + * + + + ++ +++ + * 1) PIT loop. We set the PIT Channel 2 to oneshot mode and + + + ++ +++ + * load a timeout of 50ms. We read the time right after we + + + ++ +++ + * started the timer and wait until the PIT count down reaches + + + ++ +++ + * zero. In each wait loop iteration we read the TSC and check + + + ++ +++ + * the delta to the previous read. We keep track of the min + + + ++ +++ + * and max values of that delta. The delta is mostly defined + + + ++ +++ + * by the IO time of the PIT access, so we can detect when a + + + ++ +++ + * SMI/SMM disturbance happend between the two reads. If the + + + ++ +++ + * maximum time is significantly larger than the minimum time, + + + ++ +++ + * then we discard the result and have another try. + + + ++ +++ + * + + + ++ +++ + * 2) Reference counter. If available we use the HPET or the + + + ++ +++ + * PMTIMER as a reference to check the sanity of that value. + + + ++ +++ + * We use separate TSC readouts and check inside of the + + + ++ +++ + * reference read for a SMI/SMM disturbance. We dicard + + + ++ +++ + * disturbed values here as well. We do that around the PIT + + + ++ +++ + * calibration delay loop as we have to wait for a certain + + + ++ +++ + * amount of time anyway. */ - - --- - --- - - for (i = 0; i < 5; i++) { - - - -- --- - delta = (tr2 - tr1); - - - -- --- - do_div(delta, 50); - - - -- --- - tsc_khz_val = delta; - - - -- --- - - - - -- --- - /* hpet or pmtimer available ? */ - - - -- --- - if (!hpet && !pm1 && !pm2) { - - - -- --- - printk(KERN_INFO "TSC calibrated against PIT\n"); - - - -- --- - goto out; ++++++++++++++++++ ++ ++++++++++++++++++ ++ /* Preset PIT loop values */ ++++++++++++++++++ ++ latch = CAL_LATCH; ++++++++++++++++++ ++ ms = CAL_MS; ++++++++++++++++++ ++ loopmin = CAL_PIT_LOOPS; ++++++++++++++++++ ++ ++++++++++++++++++ ++ for (i = 0; i < 3; i++) { + + + ++ +++ + unsigned long tsc_pit_khz; + + + ++ +++ + + + + ++ +++ + /* + + + ++ +++ + * Read the start value and the reference count of + + + ++ +++ + * hpet/pmtimer when available. Then do the PIT + + + ++ +++ + * calibration, which will take at least 50ms, and + + + ++ +++ + * read the end value. + + + ++ +++ + */ + + + ++ +++ + local_irq_save(flags); - - --- - --- - - tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL); - - --- - --- - - tsc_pit_khz = pit_calibrate_tsc(); - - --- - --- - - tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL); ++++++++++++++++++ ++ tsc1 = tsc_read_refs(&ref1, hpet); ++++++++++++++++++ ++ tsc_pit_khz = pit_calibrate_tsc(latch, ms, loopmin); ++++++++++++++++++ ++ tsc2 = tsc_read_refs(&ref2, hpet); + + + ++ +++ + local_irq_restore(flags); + + + ++ +++ + + + + ++ +++ + /* Pick the lowest PIT TSC calibration so far */ + + + ++ +++ + tsc_pit_min = min(tsc_pit_min, tsc_pit_khz); + + + ++ +++ + + + + ++ +++ + /* hpet or pmtimer available ? */ - - --- - --- - - if (!hpet && !pm1 && !pm2) ++++++++++++++++++ ++ if (!hpet && !ref1 && !ref2) + + + ++ +++ + continue; + + + ++ +++ + + + + ++ +++ + /* Check, whether the sampling was disturbed by an SMI */ + + + ++ +++ + if (tsc1 == ULLONG_MAX || tsc2 == ULLONG_MAX) + + + ++ +++ + continue; + + + ++ +++ + + + + ++ +++ + tsc2 = (tsc2 - tsc1) * 1000000LL; ++++++++++++++++++ ++ if (hpet) ++++++++++++++++++ ++ tsc2 = calc_hpet_ref(tsc2, ref1, ref2); ++++++++++++++++++ ++ else ++++++++++++++++++ ++ tsc2 = calc_pmtimer_ref(tsc2, ref1, ref2); + + + ++ +++ + - - --- - --- - - if (hpet) { - - --- - --- - - if (hpet2 < hpet1) - - --- - --- - - hpet2 += 0x100000000ULL; - - --- - --- - - hpet2 -= hpet1; - - --- - --- - - tsc1 = ((u64)hpet2 * hpet_readl(HPET_PERIOD)); - - --- - --- - - do_div(tsc1, 1000000); - - --- - --- - - } else { - - --- - --- - - if (pm2 < pm1) - - --- - --- - - pm2 += (u64)ACPI_PM_OVRRUN; - - --- - --- - - pm2 -= pm1; - - --- - --- - - tsc1 = pm2 * 1000000000LL; - - --- - --- - - do_div(tsc1, PMTMR_TICKS_PER_SEC); ++++++++++++++++++ ++ tsc_ref_min = min(tsc_ref_min, (unsigned long) tsc2); ++++++++++++++++++ ++ ++++++++++++++++++ ++ /* Check the reference deviation */ ++++++++++++++++++ ++ delta = ((u64) tsc_pit_min) * 100; ++++++++++++++++++ ++ do_div(delta, tsc_ref_min); ++++++++++++++++++ ++ ++++++++++++++++++ ++ /* ++++++++++++++++++ ++ * If both calibration results are inside a 10% window ++++++++++++++++++ ++ * then we can be sure, that the calibration ++++++++++++++++++ ++ * succeeded. We break out of the loop right away. We ++++++++++++++++++ ++ * use the reference value, as it is more precise. ++++++++++++++++++ ++ */ ++++++++++++++++++ ++ if (delta >= 90 && delta <= 110) { ++++++++++++++++++ ++ printk(KERN_INFO ++++++++++++++++++ ++ "TSC: PIT calibration matches %s. %d loops\n", ++++++++++++++++++ ++ hpet ? "HPET" : "PMTIMER", i + 1); ++++++++++++++++++ ++ return tsc_ref_min; + + + ++ +++ + } + + + ++ +++ + - - --- - --- - - do_div(tsc2, tsc1); - - --- - --- - - tsc_ref_min = min(tsc_ref_min, (unsigned long) tsc2); ++++++++++++++++++ ++ /* ++++++++++++++++++ ++ * Check whether PIT failed more than once. This ++++++++++++++++++ ++ * happens in virtualized environments. We need to ++++++++++++++++++ ++ * give the virtual PC a slightly longer timeframe for ++++++++++++++++++ ++ * the HPET/PMTIMER to make the result precise. ++++++++++++++++++ ++ */ ++++++++++++++++++ ++ if (i == 1 && tsc_pit_min == ULONG_MAX) { ++++++++++++++++++ ++ latch = CAL2_LATCH; ++++++++++++++++++ ++ ms = CAL2_MS; ++++++++++++++++++ ++ loopmin = CAL2_PIT_LOOPS; ++++++++++++++++++ ++ } } - - - -- --- - /* Check, whether the sampling was disturbed by an SMI */ - - - -- --- - if (tsc1 == ULLONG_MAX || tsc2 == ULLONG_MAX) { - - - -- --- - printk(KERN_WARNING "TSC calibration disturbed by SMI, " - - - -- --- - "using PIT calibration result\n"); - - - -- --- - goto out; + + + ++ +++ + /* + + + ++ +++ + * Now check the results. + + + ++ +++ + */ + + + ++ +++ + if (tsc_pit_min == ULONG_MAX) { + + + ++ +++ + /* PIT gave no useful value */ - printk(KERN_WARNING "TSC: PIT calibration failed due to " - "SMI disturbance.\n"); + + + ++ +++ + + printk(KERN_WARNING "TSC: Unable to calibrate against PIT\n"); + + + ++ +++ + + + + ++ +++ + /* We don't have an alternative source, disable TSC */ - - --- - --- - - if (!hpet && !pm1 && !pm2) { ++++++++++++++++++ ++ if (!hpet && !ref1 && !ref2) { + + + ++ +++ + printk("TSC: No reference (HPET/PMTIMER) available\n"); + + + ++ +++ + return 0; + + + ++ +++ + } + + + ++ +++ + + + + ++ +++ + /* The alternative source failed as well, disable TSC */ + + + ++ +++ + if (tsc_ref_min == ULONG_MAX) { + + + ++ +++ + printk(KERN_WARNING "TSC: HPET/PMTIMER calibration " - - --- - --- - - "failed due to SMI disturbance.\n"); ++++++++++++++++++ ++ "failed.\n"); + + + ++ +++ + return 0; + + + ++ +++ + } + + + ++ +++ + + + + ++ +++ + /* Use the alternative source */ + + + ++ +++ + printk(KERN_INFO "TSC: using %s reference calibration\n", + + + ++ +++ + hpet ? "HPET" : "PMTIMER"); + + + ++ +++ + + + + ++ +++ + return tsc_ref_min; } - - - -- --- - tsc2 = (tsc2 - tsc1) * 1000000LL; - - - -- --- - - - - -- --- - if (hpet) { - - - -- --- - printk(KERN_INFO "TSC calibrated against HPET\n"); - - - -- --- - if (hpet2 < hpet1) - - - -- --- - hpet2 += 0x100000000ULL; - - - -- --- - hpet2 -= hpet1; - - - -- --- - tsc1 = ((u64)hpet2 * hpet_readl(HPET_PERIOD)); - - - -- --- - do_div(tsc1, 1000000); - - - -- --- - } else { - - - -- --- - printk(KERN_INFO "TSC calibrated against PM_TIMER\n"); - - - -- --- - if (pm2 < pm1) - - - -- --- - pm2 += (u64)ACPI_PM_OVRRUN; - - - -- --- - pm2 -= pm1; - - - -- --- - tsc1 = pm2 * 1000000000LL; - - - -- --- - do_div(tsc1, PMTMR_TICKS_PER_SEC); + + + ++ +++ + /* We don't have an alternative source, use the PIT calibration value */ - - --- - --- - - if (!hpet && !pm1 && !pm2) { ++++++++++++++++++ ++ if (!hpet && !ref1 && !ref2) { + + + ++ +++ + printk(KERN_INFO "TSC: Using PIT calibration value\n"); + + + ++ +++ + return tsc_pit_min; } - - - -- --- - do_div(tsc2, tsc1); - - - -- --- - tsc_khz_val = tsc2; + + + ++ +++ + /* The alternative source failed, use the PIT calibration value */ + + + ++ +++ + if (tsc_ref_min == ULONG_MAX) { - - --- - --- - - printk(KERN_WARNING "TSC: HPET/PMTIMER calibration failed due " - - --- - --- - - "to SMI disturbance. Using PIT calibration\n"); ++++++++++++++++++ ++ printk(KERN_WARNING "TSC: HPET/PMTIMER calibration failed. " ++++++++++++++++++ ++ "Using PIT calibration\n"); + + + ++ +++ + return tsc_pit_min; + + + ++ +++ + } - - --- - --- - - /* Check the reference deviation */ - - --- - --- - - delta = ((u64) tsc_pit_min) * 100; - - --- - --- - - do_div(delta, tsc_ref_min); - - --- - --- - - - - --- - --- - - /* - - --- - --- - - * If both calibration results are inside a 5% window, the we - - --- - --- - - * use the lower frequency of those as it is probably the - - --- - --- - - * closest estimate. - - --- - --- - - */ - - --- - --- - - if (delta >= 95 && delta <= 105) { - - --- - --- - - printk(KERN_INFO "TSC: PIT calibration confirmed by %s.\n", - - --- - --- - - hpet ? "HPET" : "PMTIMER"); - - --- - --- - - printk(KERN_INFO "TSC: using %s calibration value\n", - - --- - --- - - tsc_pit_min <= tsc_ref_min ? "PIT" : - - --- - --- - - hpet ? "HPET" : "PMTIMER"); - - --- - --- - - return tsc_pit_min <= tsc_ref_min ? tsc_pit_min : tsc_ref_min; - - --- - --- - - } - - --- - --- - - - - --- - --- - - printk(KERN_WARNING "TSC: PIT calibration deviates from %s: %lu %lu.\n", - - --- - --- - - hpet ? "HPET" : "PMTIMER", tsc_pit_min, tsc_ref_min); - - --- - --- - - - - - -- --- -out: - - - -- --- - return tsc_khz_val; + + + ++ +++ + /* + + + ++ +++ + * The calibration values differ too much. In doubt, we use + + + ++ +++ + * the PIT value as we know that there are PMTIMERs around - - --- - --- - - * running at double speed. ++++++++++++++++++ ++ * running at double speed. At least we let the user know: + + + ++ +++ + */ ++++++++++++++++++ ++ printk(KERN_WARNING "TSC: PIT calibration deviates from %s: %lu %lu.\n", ++++++++++++++++++ ++ hpet ? "HPET" : "PMTIMER", tsc_pit_min, tsc_ref_min); + + + ++ +++ + printk(KERN_INFO "TSC: Using PIT calibration value\n"); + + + ++ +++ + return tsc_pit_min; } - - - -- --- - #ifdef CONFIG_X86_32 /* Only called from the Powernow K7 cpu freq driver */ int recalibrate_cpu_khz(void) diff --cc include/asm-x86/mach-rdc321x/gpio.h index 6184561980f2,acce0b7d397b,acce0b7d397b,acce0b7d397b,acce0b7d397b,3639ece6485a,acce0b7d397b,acce0b7d397b,acce0b7d397b,acce0b7d397b,acce0b7d397b,acce0b7d397b,acce0b7d397b,acce0b7d397b,acce0b7d397b,acce0b7d397b,acce0b7d397b,acce0b7d397b,acce0b7d397b,acce0b7d397b,acce0b7d397b..94b6cdf532e2 --- a/include/asm-x86/mach-rdc321x/gpio.h +++ b/include/asm-x86/mach-rdc321x/gpio.h @@@@@@@@@@@@@@@@@@@@@@ -1,6 -1,6 -1,6 -1,6 -1,6 -1,8 -1,6 -1,6 -1,6 -1,6 -1,6 -1,6 -1,6 -1,6 -1,6 -1,6 -1,6 -1,6 -1,6 -1,6 -1,6 +1,8 @@@@@@@@@@@@@@@@@@@@@@ --------------------#ifndef _RDC321X_GPIO_H --------------------#define _RDC321X_GPIO_H ++++++++++++++++++++#ifndef ASM_X86__MACH_RDC321X__GPIO_H ++++++++++++++++++++#define ASM_X86__MACH_RDC321X__GPIO_H ++++ +++++++++++++++ +++++ +++++++++++++++#include + extern int rdc_gpio_get_value(unsigned gpio); extern void rdc_gpio_set_value(unsigned gpio, int value); extern int rdc_gpio_direction_input(unsigned gpio); diff --cc include/asm-x86/msr.h index eee83f783f6d,ca110ee73f07,2362cfda1fbc,ca110ee73f07,2362cfda1fbc,771bcb2f8d80,2362cfda1fbc,ca110ee73f07,2362cfda1fbc,ca110ee73f07,ca110ee73f07,2362cfda1fbc,2362cfda1fbc,2362cfda1fbc,ca110ee73f07,ca110ee73f07,ca110ee73f07,2362cfda1fbc,2362cfda1fbc,2362cfda1fbc,ca110ee73f07..530af1f6389e --- a/include/asm-x86/msr.h +++ b/include/asm-x86/msr.h @@@@@@@@@@@@@@@@@@@@@@ -52,17 -52,17 -52,17 -52,17 -52,17 -52,33 -52,17 -52,17 -52,17 -52,17 -52,17 -52,17 -52,17 -52,17 -52,17 -52,17 -52,17 -52,17 -52,17 -52,17 -52,17 +52,33 @@@@@@@@@@@@@@@@@@@@@@ static inline unsigned long long native { DECLARE_ARGS(val, low, high); + + + ++ +++ + asm volatile("2: rdmsr ; xor %[err],%[err]\n" + + + ++ +++ + "1:\n\t" + + + ++ +++ + ".section .fixup,\"ax\"\n\t" + + + ++ +++ + "3: mov %[fault],%[err] ; jmp 1b\n\t" + + + ++ +++ + ".previous\n\t" + + + ++ +++ + _ASM_EXTABLE(2b, 3b) + + + ++ +++ + : [err] "=r" (*err), EAX_EDX_RET(val, low, high) + + + ++ +++ + : "c" (msr), [fault] "i" (-EFAULT)); + + + ++ +++ + return EAX_EDX_VAL(val, low, high); + + + ++ +++ +} + + + ++ +++ + +++++ +++++++++++++++static inline unsigned long long native_read_msr_amd_safe(unsigned int msr, +++++ +++++++++++++++ int *err) +++++ +++++++++++++++{ +++++ +++++++++++++++ DECLARE_ARGS(val, low, high); +++++ +++++++++++++++ + + + + + +++ +++ asm volatile("2: rdmsr ; xor %0,%0\n" + + + + + +++ +++ "1:\n\t" + + + + + +++ +++ ".section .fixup,\"ax\"\n\t" + + + + + +++ +++ "3: mov %3,%0 ; jmp 1b\n\t" + + + + + +++ +++ ".previous\n\t" + + + + + +++ +++ _ASM_EXTABLE(2b, 3b) + + + + + +++ +++ : "=r" (*err), EAX_EDX_RET(val, low, high) - - - -- --- - : "c" (msr), "i" (-EFAULT)); +++++ +++++++++++++++ : "c" (msr), "D" (0x9c5a203a), "i" (-EFAULT)); + + + + + +++ +++ return EAX_EDX_VAL(val, low, high); + + + + + +++ +++ } + + + + + +++ +++ static inline void native_write_msr(unsigned int msr, unsigned low, unsigned high) {