aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2010-08-11 16:44:03 +0100
committerKeir Fraser <keir.fraser@citrix.com>2010-08-11 16:44:03 +0100
commit82c6982d50a89a709a0c3ecf0f63dc5c572849ed (patch)
tree853ffc0daa1796f94fe57244c9e701768ba77d4e
parent6007502b5726d833d15d06c231f4a46f001da3ca (diff)
downloadxen-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.c36
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;