summaryrefslogtreecommitdiffstats
path: root/sys/x86/x86/local_apic.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/x86/x86/local_apic.c')
-rw-r--r--sys/x86/x86/local_apic.c49
1 files changed, 34 insertions, 15 deletions
diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c
index 5830b77..854bda4 100644
--- a/sys/x86/x86/local_apic.c
+++ b/sys/x86/x86/local_apic.c
@@ -170,7 +170,7 @@ vm_paddr_t lapic_paddr;
int x2apic_mode;
int lapic_eoi_suppression;
static int lapic_timer_tsc_deadline;
-static u_long lapic_timer_divisor;
+static u_long lapic_timer_divisor, count_freq;
static struct eventtimer lapic_et;
#ifdef SMP
static uint64_t lapic_ipi_wait_mult;
@@ -814,20 +814,46 @@ lapic_calibrate_initcount(struct eventtimer *et, struct lapic *la)
printf("lapic: Divisor %lu, Frequency %lu Hz\n",
lapic_timer_divisor, value);
}
- et->et_frequency = value;
+ count_freq = value;
}
static void
lapic_calibrate_deadline(struct eventtimer *et, struct lapic *la __unused)
{
- et->et_frequency = tsc_freq;
if (bootverbose) {
printf("lapic: deadline tsc mode, Frequency %ju Hz\n",
- (uintmax_t)et->et_frequency);
+ (uintmax_t)tsc_freq);
}
}
+static void
+lapic_change_mode(struct eventtimer *et, struct lapic *la,
+ enum lat_timer_mode newmode)
+{
+
+ if (la->la_timer_mode == newmode)
+ return;
+ switch (newmode) {
+ case LAT_MODE_PERIODIC:
+ lapic_timer_set_divisor(lapic_timer_divisor);
+ et->et_frequency = count_freq;
+ break;
+ case LAT_MODE_DEADLINE:
+ et->et_frequency = tsc_freq;
+ break;
+ case LAT_MODE_ONESHOT:
+ lapic_timer_set_divisor(lapic_timer_divisor);
+ et->et_frequency = count_freq;
+ break;
+ default:
+ panic("lapic_change_mode %d", newmode);
+ }
+ la->la_timer_mode = newmode;
+ et->et_min_period = (0x00000002LLU << 32) / et->et_frequency;
+ et->et_max_period = (0xfffffffeLLU << 32) / et->et_frequency;
+}
+
static int
lapic_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
{
@@ -835,28 +861,21 @@ lapic_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
la = &lapics[PCPU_GET(apic_id)];
if (et->et_frequency == 0) {
+ lapic_calibrate_initcount(et, la);
if (lapic_timer_tsc_deadline)
lapic_calibrate_deadline(et, la);
- else
- lapic_calibrate_initcount(et, la);
- et->et_min_period = (0x00000002LLU << 32) / et->et_frequency;
- et->et_max_period = (0xfffffffeLLU << 32) / et->et_frequency;
}
if (period != 0) {
- if (la->la_timer_mode == LAT_MODE_UNDEF)
- lapic_timer_set_divisor(lapic_timer_divisor);
- la->la_timer_mode = LAT_MODE_PERIODIC;
+ lapic_change_mode(et, la, LAT_MODE_PERIODIC);
la->la_timer_period = ((uint32_t)et->et_frequency * period) >>
32;
lapic_timer_periodic(la);
} else if (lapic_timer_tsc_deadline) {
- la->la_timer_mode = LAT_MODE_DEADLINE;
+ lapic_change_mode(et, la, LAT_MODE_DEADLINE);
la->la_timer_period = (et->et_frequency * first) >> 32;
lapic_timer_deadline(la);
} else {
- if (la->la_timer_mode == LAT_MODE_UNDEF)
- lapic_timer_set_divisor(lapic_timer_divisor);
- la->la_timer_mode = LAT_MODE_ONESHOT;
+ lapic_change_mode(et, la, LAT_MODE_ONESHOT);
la->la_timer_period = ((uint32_t)et->et_frequency * first) >>
32;
lapic_timer_oneshot(la);
OpenPOWER on IntegriCloud