diff options
author | Alexander Motin <mav@FreeBSD.org> | 2011-05-05 18:56:48 +0000 |
---|---|---|
committer | Alexander Motin <mav@FreeBSD.org> | 2011-05-05 18:56:48 +0000 |
commit | 00aa5aab1eadb456a3a072adbb4596dc708d249b (patch) | |
tree | 10fcbfb62cf1383754b14d7b462146d295e5de42 /sys/x86 | |
parent | 7798640d82ceaf7b138efc2373d153b57481a714 (diff) | |
download | src-00aa5aab1eadb456a3a072adbb4596dc708d249b.tar.gz src-00aa5aab1eadb456a3a072adbb4596dc708d249b.zip |
Some changes around LAPIC timer programming.
This fixes heavy interrupt storm and resulting system freeze when using
LAPIC timer in one-shot mode under Xen HVM. There, unlike real hardware,
programming timer with zero period almost immediately causes interrupt.
Notes
Notes:
svn path=/head/; revision=221508
Diffstat (limited to 'sys/x86')
-rw-r--r-- | sys/x86/x86/local_apic.c | 38 |
1 files changed, 13 insertions, 25 deletions
diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c index 804c411b951c..f5ac443577f5 100644 --- a/sys/x86/x86/local_apic.c +++ b/sys/x86/x86/local_apic.c @@ -159,9 +159,8 @@ static struct eventtimer lapic_et; static void lapic_enable(void); static void lapic_resume(struct pic *pic); -static void lapic_timer_enable_intr(void); -static void lapic_timer_oneshot(u_int count); -static void lapic_timer_periodic(u_int count); +static void lapic_timer_oneshot(u_int count, int enable_int); +static void lapic_timer_periodic(u_int count, int enable_int); static void lapic_timer_stop(void); static void lapic_timer_set_divisor(u_int divisor); static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value); @@ -379,13 +378,11 @@ lapic_setup(int boot) if (la->la_timer_mode != 0) { KASSERT(la->la_timer_period != 0, ("lapic%u: zero divisor", lapic_id())); - lapic_timer_stop(); lapic_timer_set_divisor(lapic_timer_divisor); - lapic_timer_enable_intr(); if (la->la_timer_mode == 1) - lapic_timer_periodic(la->la_timer_period); + lapic_timer_periodic(la->la_timer_period, 1); else - lapic_timer_oneshot(la->la_timer_period); + lapic_timer_oneshot(la->la_timer_period, 1); } /* Program error LVT and clear any existing errors. */ @@ -496,7 +493,7 @@ lapic_et_start(struct eventtimer *et, /* Try to calibrate the local APIC timer. */ do { lapic_timer_set_divisor(lapic_timer_divisor); - lapic_timer_oneshot(APIC_TIMER_MAX_COUNT); + lapic_timer_oneshot(APIC_TIMER_MAX_COUNT, 0); DELAY(1000000); value = APIC_TIMER_MAX_COUNT - lapic->ccr_timer; if (value != APIC_TIMER_MAX_COUNT) @@ -516,9 +513,7 @@ lapic_et_start(struct eventtimer *et, et->et_max_period.frac = ((0xfffffffeLLU << 32) / et->et_frequency) << 32; } - lapic_timer_stop(); lapic_timer_set_divisor(lapic_timer_divisor); - lapic_timer_enable_intr(); la = &lapics[lapic_id()]; if (period != NULL) { la->la_timer_mode = 1; @@ -526,14 +521,14 @@ lapic_et_start(struct eventtimer *et, (et->et_frequency * (period->frac >> 32)) >> 32; if (period->sec != 0) la->la_timer_period += et->et_frequency * period->sec; - lapic_timer_periodic(la->la_timer_period); + lapic_timer_periodic(la->la_timer_period, 1); } else { la->la_timer_mode = 2; la->la_timer_period = (et->et_frequency * (first->frac >> 32)) >> 32; if (first->sec != 0) la->la_timer_period += et->et_frequency * first->sec; - lapic_timer_oneshot(la->la_timer_period); + lapic_timer_oneshot(la->la_timer_period, 1); } return (0); } @@ -838,25 +833,29 @@ lapic_timer_set_divisor(u_int divisor) } static void -lapic_timer_oneshot(u_int count) +lapic_timer_oneshot(u_int count, int enable_int) { u_int32_t value; value = lapic->lvt_timer; value &= ~APIC_LVTT_TM; value |= APIC_LVTT_TM_ONE_SHOT; + if (enable_int) + value &= ~APIC_LVT_M; lapic->lvt_timer = value; lapic->icr_timer = count; } static void -lapic_timer_periodic(u_int count) +lapic_timer_periodic(u_int count, int enable_int) { u_int32_t value; value = lapic->lvt_timer; value &= ~APIC_LVTT_TM; value |= APIC_LVTT_TM_PERIODIC; + if (enable_int) + value &= ~APIC_LVT_M; lapic->lvt_timer = value; lapic->icr_timer = count; } @@ -870,17 +869,6 @@ lapic_timer_stop(void) value &= ~APIC_LVTT_TM; value |= APIC_LVT_M; lapic->lvt_timer = value; - lapic->icr_timer = 0; -} - -static void -lapic_timer_enable_intr(void) -{ - u_int32_t value; - - value = lapic->lvt_timer; - value &= ~APIC_LVT_M; - lapic->lvt_timer = value; } void |