aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/x86/x86/local_apic.c43
1 files changed, 24 insertions, 19 deletions
diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c
index 99a681b01044..e9941729463a 100644
--- a/sys/x86/x86/local_apic.c
+++ b/sys/x86/x86/local_apic.c
@@ -119,6 +119,7 @@ struct lapic {
u_long *la_timer_count;
u_long la_timer_period;
u_int la_timer_mode;
+ uint32_t lvt_timer_cache;
/* Include IDT_SYSCALL to make indexing easier. */
int la_ioint_irqs[APIC_NUM_IOINTS + 1];
} static lapics[MAX_APIC_ID + 1];
@@ -160,9 +161,11 @@ static struct eventtimer lapic_et;
static void lapic_enable(void);
static void lapic_resume(struct pic *pic);
-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_oneshot(struct lapic *,
+ u_int count, int enable_int);
+static void lapic_timer_periodic(struct lapic *,
+ u_int count, int enable_int);
+static void lapic_timer_stop(struct lapic *);
static void lapic_timer_set_divisor(u_int divisor);
static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value);
static int lapic_et_start(struct eventtimer *et,
@@ -370,7 +373,8 @@ lapic_setup(int boot)
lapic->lvt_pcint = lvt_mode(la, LVT_PMC, lapic->lvt_pcint);
/* Program timer LVT and setup handler. */
- lapic->lvt_timer = lvt_mode(la, LVT_TIMER, lapic->lvt_timer);
+ la->lvt_timer_cache = lapic->lvt_timer =
+ lvt_mode(la, LVT_TIMER, lapic->lvt_timer);
if (boot) {
snprintf(buf, sizeof(buf), "cpu%d:timer", PCPU_GET(cpuid));
intrcnt_add(buf, &la->la_timer_count);
@@ -382,9 +386,9 @@ lapic_setup(int boot)
lapic_id()));
lapic_timer_set_divisor(lapic_timer_divisor);
if (la->la_timer_mode == 1)
- lapic_timer_periodic(la->la_timer_period, 1);
+ lapic_timer_periodic(la, la->la_timer_period, 1);
else
- lapic_timer_oneshot(la->la_timer_period, 1);
+ lapic_timer_oneshot(la, la->la_timer_period, 1);
}
/* Program error LVT and clear any existing errors. */
@@ -489,13 +493,14 @@ lapic_et_start(struct eventtimer *et,
struct lapic *la;
u_long value;
+ la = &lapics[PCPU_GET(apic_id)];
if (et->et_frequency == 0) {
/* Start off with a divisor of 2 (power on reset default). */
lapic_timer_divisor = 2;
/* Try to calibrate the local APIC timer. */
do {
lapic_timer_set_divisor(lapic_timer_divisor);
- lapic_timer_oneshot(APIC_TIMER_MAX_COUNT, 0);
+ lapic_timer_oneshot(la, APIC_TIMER_MAX_COUNT, 0);
DELAY(1000000);
value = APIC_TIMER_MAX_COUNT - lapic->ccr_timer;
if (value != APIC_TIMER_MAX_COUNT)
@@ -515,22 +520,22 @@ lapic_et_start(struct eventtimer *et,
et->et_max_period.frac =
((0xfffffffeLLU << 32) / et->et_frequency) << 32;
}
- lapic_timer_set_divisor(lapic_timer_divisor);
- la = &lapics[lapic_id()];
+ if (la->la_timer_mode == 0)
+ lapic_timer_set_divisor(lapic_timer_divisor);
if (period != NULL) {
la->la_timer_mode = 1;
la->la_timer_period =
(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, 1);
+ lapic_timer_periodic(la, 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, 1);
+ lapic_timer_oneshot(la, la->la_timer_period, 1);
}
return (0);
}
@@ -538,10 +543,10 @@ lapic_et_start(struct eventtimer *et,
static int
lapic_et_stop(struct eventtimer *et)
{
- struct lapic *la = &lapics[lapic_id()];
+ struct lapic *la = &lapics[PCPU_GET(apic_id)];
la->la_timer_mode = 0;
- lapic_timer_stop();
+ lapic_timer_stop(la);
return (0);
}
@@ -835,11 +840,11 @@ lapic_timer_set_divisor(u_int divisor)
}
static void
-lapic_timer_oneshot(u_int count, int enable_int)
+lapic_timer_oneshot(struct lapic *la, u_int count, int enable_int)
{
u_int32_t value;
- value = lapic->lvt_timer;
+ value = la->lvt_timer_cache;
value &= ~APIC_LVTT_TM;
value |= APIC_LVTT_TM_ONE_SHOT;
if (enable_int)
@@ -849,11 +854,11 @@ lapic_timer_oneshot(u_int count, int enable_int)
}
static void
-lapic_timer_periodic(u_int count, int enable_int)
+lapic_timer_periodic(struct lapic *la, u_int count, int enable_int)
{
u_int32_t value;
- value = lapic->lvt_timer;
+ value = la->lvt_timer_cache;
value &= ~APIC_LVTT_TM;
value |= APIC_LVTT_TM_PERIODIC;
if (enable_int)
@@ -863,11 +868,11 @@ lapic_timer_periodic(u_int count, int enable_int)
}
static void
-lapic_timer_stop(void)
+lapic_timer_stop(struct lapic *la)
{
u_int32_t value;
- value = lapic->lvt_timer;
+ value = la->lvt_timer_cache;
value &= ~APIC_LVTT_TM;
value |= APIC_LVT_M;
lapic->lvt_timer = value;