diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2010-08-11 16:44:03 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2010-08-11 16:44:03 +0100 |
commit | 82c6982d50a89a709a0c3ecf0f63dc5c572849ed (patch) | |
tree | 853ffc0daa1796f94fe57244c9e701768ba77d4e | |
parent | 6007502b5726d833d15d06c231f4a46f001da3ca (diff) | |
download | xen-82c6982d50a89a709a0c3ecf0f63dc5c572849ed.tar.gz xen-82c6982d50a89a709a0c3ecf0f63dc5c572849ed.tar.bz2 xen-82c6982d50a89a709a0c3ecf0f63dc5c572849ed.zip |
x86: Detect and handle unexpected platform-timer counter wrap.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
xen-unstable changeset: 21346:7d4deb86b966
xen-unstable date: Tue May 11 11:21:27 2010 +0100
-rw-r--r-- | xen/arch/x86/time.c | 36 |
1 files changed, 29 insertions, 7 deletions
diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index 16e4200559..6264a648d5 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -571,26 +571,48 @@ static u64 plt_stamp64; /* 64-bit platform counter stamp */ static u64 plt_stamp; /* hardware-width platform counter stamp */ static struct timer plt_overflow_timer; +static s_time_t __read_platform_stime(u64 platform_time) +{ + u64 diff = platform_time - platform_timer_stamp; + ASSERT(spin_is_locked(&platform_timer_lock)); + return (stime_platform_stamp + scale_delta(diff, &plt_scale)); +} + static void plt_overflow(void *unused) { + int i; u64 count; + s_time_t now, plt_now, plt_wrap; spin_lock_irq(&platform_timer_lock); + count = plt_src.read_counter(); plt_stamp64 += (count - plt_stamp) & plt_mask; plt_stamp = count; + + now = NOW(); + plt_wrap = __read_platform_stime(plt_stamp64); + for ( i = 0; i < 10; i++ ) + { + plt_now = plt_wrap; + plt_wrap = __read_platform_stime(plt_stamp64 + plt_mask + 1); + if ( ABS(plt_wrap - now) > ABS(plt_now - now) ) + break; + plt_stamp64 += plt_mask + 1; + } + if ( i != 0 ) + { + static bool_t warned_once; + if ( !test_and_set_bool(warned_once) ) + printk("Platform timer appears to have unexpectedly wrapped " + "%u%s times.\n", i, (i == 10) ? " or more" : ""); + } + spin_unlock_irq(&platform_timer_lock); set_timer(&plt_overflow_timer, NOW() + plt_overflow_period); } -static s_time_t __read_platform_stime(u64 platform_time) -{ - u64 diff = platform_time - platform_timer_stamp; - ASSERT(spin_is_locked(&platform_timer_lock)); - return (stime_platform_stamp + scale_delta(diff, &plt_scale)); -} - static s_time_t read_platform_stime(void) { u64 count; |