aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/apic.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2009-11-03 09:33:22 +0000
committerKeir Fraser <keir.fraser@citrix.com>2009-11-03 09:33:22 +0000
commitb95beb185810484d5afe91b994d2c2d1670af74c (patch)
treedf43239616fdab10f7593af4deb1509b397f50e8 /xen/arch/x86/apic.c
parentad1f74192ab40866396316cd86bec3f98b6ef56b (diff)
downloadxen-b95beb185810484d5afe91b994d2c2d1670af74c.tar.gz
xen-b95beb185810484d5afe91b994d2c2d1670af74c.tar.bz2
xen-b95beb185810484d5afe91b994d2c2d1670af74c.zip
x86: Clean up APIC local timer handling.
1. Writing TMICT=0 disables the timer. Use this fact to simplify and improve reprogram_timer(). In particular, we always write TMICT, and write zero when we do not need a timer interrupt. 2. In HPET broadcast timer handler, set TMICT=0 when we mask the APIC local timer. May as well do this early, before entering deep sleep. 3. In HVM-guest APIC emulation, disable the emulated local timer when the guest sets TMICT=0. Previously we would issue an immediate one-shot interrupt. Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Diffstat (limited to 'xen/arch/x86/apic.c')
-rw-r--r--xen/arch/x86/apic.c58
1 files changed, 9 insertions, 49 deletions
diff --git a/xen/arch/x86/apic.c b/xen/arch/x86/apic.c
index b9004413a8..64be332ca6 100644
--- a/xen/arch/x86/apic.c
+++ b/xen/arch/x86/apic.c
@@ -1178,65 +1178,25 @@ void enable_APIC_timer(void)
#undef APIC_DIVISOR
/*
- * reprogram the APIC timer. Timeoutvalue is in ns from start of boot
- * returns 1 on success
- * returns 0 if the timeout value is too small or in the past.
+ * reprogram_timer: Reprogram the APIC timer.
+ * Timeout is a Xen system time (nanoseconds since boot); 0 disables the timer.
+ * Returns 1 on success; 0 if the timeout is too soon or is in the past.
*/
int reprogram_timer(s_time_t timeout)
{
- s_time_t now;
- s_time_t expire;
- u64 apic_tmict;
+ s_time_t expire;
+ u32 apic_tmict = 0;
- /*
- * If we don't have local APIC then we just poll the timer list off the
- * PIT interrupt.
- */
+ /* No local APIC: timer list is polled via the PIT interrupt. */
if ( !cpu_has_apic )
return 1;
- /*
- * We use this value because we don't trust zero (we think it may just
- * cause an immediate interrupt). At least this is guaranteed to hold it
- * off for ages (esp. since the clock ticks on bus clock, not cpu clock!).
- */
- if ( timeout == 0 )
- {
- apic_tmict = 0xffffffff;
- goto reprogram;
- }
-
- now = NOW();
- expire = timeout - now; /* value from now */
-
- if ( expire <= 0 )
- {
- Dprintk("APICT[%02d] Timeout in the past 0x%08X%08X > 0x%08X%08X\n",
- smp_processor_id(), (u32)(now>>32),
- (u32)now, (u32)(timeout>>32),(u32)timeout);
- return 0;
- }
-
- /* conversion to bus units */
- apic_tmict = (((u64)bus_scale) * expire)>>18;
-
- if ( apic_tmict >= 0xffffffff )
- {
- Dprintk("APICT[%02d] Timeout value too large\n", smp_processor_id());
- apic_tmict = 0xffffffff;
- }
-
- if ( apic_tmict == 0 )
- {
- Dprintk("APICT[%02d] timeout value too small\n", smp_processor_id());
- return 0;
- }
+ if ( timeout && ((expire = timeout - NOW()) > 0) )
+ apic_tmict = min_t(u64, (bus_scale * expire) >> 18, UINT_MAX);
- reprogram:
- /* Program the timer. */
apic_write(APIC_TMICT, (unsigned long)apic_tmict);
- return 1;
+ return apic_tmict || !timeout;
}
fastcall void smp_apic_timer_interrupt(struct cpu_user_regs * regs)