summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--i386/i386/apic.h3
-rw-r--r--i386/i386at/ioapic.c81
-rw-r--r--i386/i386at/model_dep.c8
3 files changed, 54 insertions, 38 deletions
diff --git a/i386/i386/apic.h b/i386/i386/apic.h
index ac083d26..a79f0ea8 100644
--- a/i386/i386/apic.h
+++ b/i386/i386/apic.h
@@ -243,11 +243,12 @@ void lapic_eoi(void);
void ioapic_irq_eoi(int pin);
void lapic_enable(void);
void lapic_enable_timer(void);
+void calibrate_lapic_timer(void);
void ioapic_mask_irqs(void);
void ioapic_toggle(int pin, int mask);
void ioapic_configure(void);
-extern int duplicate_pin;
+extern int timer_pin;
extern void intnull(int unit);
extern volatile ApicLocalUnit* lapic;
diff --git a/i386/i386at/ioapic.c b/i386/i386at/ioapic.c
index d2ea84ad..c6da35e1 100644
--- a/i386/i386at/ioapic.c
+++ b/i386/i386at/ioapic.c
@@ -28,11 +28,13 @@
#include <i386/pio.h>
#include <i386/pit.h>
#include <i386/pic.h> /* only for macros */
+#include <i386/smp.h>
#include <mach/machine.h>
#include <kern/printf.h>
+#include <kern/timer.h>
static int has_irq_specific_eoi = 1; /* FIXME: Assume all machines have this */
-int duplicate_pin;
+int timer_pin;
uint32_t lapic_timer_val = 0;
uint32_t calibrated_ticks = 0;
@@ -43,7 +45,7 @@ int iunit[NINTR] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23};
interrupt_handler_fn ivect[NINTR] = {
- /* 00 */ intnull, /* install timer later */
+ /* 00 */ (interrupt_handler_fn)hardclock,
/* 01 */ kdintr, /* kdintr, ... */
/* 02 */ intnull,
/* 03 */ intnull, /* lnpoll, comintr, ... */
@@ -150,32 +152,58 @@ ioapic_toggle_entry(int apic, int pin, int mask)
ioapic_write(apic, APIC_IO_REDIR_LOW(pin), entry.lo);
}
+static void timer_expiry_callback(void *arg)
+{
+ volatile int *done = arg;
+ *done = 1;
+}
+
static uint32_t
-pit_measure_10x_apic_hz(void)
+timer_measure_10x_apic_hz(void)
{
- volatile int i;
+ volatile int done = 0;
uint32_t start = 0xffffffff;
+ timer_elt_data_t tmp_timer;
+ tmp_timer.fcn = timer_expiry_callback;
+ tmp_timer.param = (void *)&done;
- /* Prepare accurate delay for 1/hz seconds */
- pit_prepare_sleep(hz);
+ printf("timer calibration...");
/* Set APIC timer */
lapic->init_count.r = start;
- /* zZz */
- for (i = 0; i < 10; i++)
- pit_sleep();
+ /* Delay for 10 * 1/hz seconds */
+ set_timeout(&tmp_timer, hz / 10);
+ do {
+ cpu_pause();
+ } while (!done);
/* Stop APIC timer */
lapic->lvt_timer.r |= LAPIC_DISABLE;
+ printf(" done\n");
+
return start - lapic->cur_count.r;
}
-void lapic_update_timer(void)
+void
+calibrate_lapic_timer(void)
{
- /* Timer decrements until zero and then calls this on every interrupt */
- lapic_timer_val += calibrated_ticks;
+ spl_t s;
+
+ /* Set one-shot timer */
+ lapic->divider_config.r = LAPIC_TIMER_DIVIDE_2;
+ lapic->lvt_timer.r = IOAPIC_INT_BASE;
+
+ /* Measure number of APIC timer ticks in 10x 1/hz seconds
+ * but calibrate the timer to expire at rate of hz
+ * divide by 10 because we waited 10 times longer than we needed. */
+ if (!calibrated_ticks) {
+ s = splhigh();
+ spl0();
+ calibrated_ticks = timer_measure_10x_apic_hz() / 10;
+ splx(s);
+ }
}
void
@@ -306,16 +334,14 @@ ioapic_configure(void)
/* Save timer info */
timer_gsi = gsi;
} else {
- /* Disable duplicated timer gsi */
+ /* Remap timer irq */
if (gsi == timer_gsi) {
- duplicate_pin = pin;
- /* Remap this interrupt pin to GSI base
- * so we don't duplicate vectors */
+ timer_pin = pin;
+ /* Remap GSI base to timer pin so ivect[0] is the timer */
entry.both.vector = IOAPIC_INT_BASE;
- ioapic_write_entry(apic, duplicate_pin, entry.both);
- /* Mask the ioapic pin with deduplicated vector as
- * we will never use it, since timer is on another gsi */
- mask_irq(duplicate_pin);
+ ioapic_write_entry(apic, timer_pin, entry.both);
+ /* Mask the duplicate pin 0 as we will be using timer_pin */
+ mask_irq(0);
}
}
}
@@ -337,20 +363,5 @@ ioapic_configure(void)
/* Start the IO APIC receiving interrupts */
lapic_enable();
- /* Set one-shot timer */
- lapic->divider_config.r = LAPIC_TIMER_DIVIDE_2;
- lapic->lvt_timer.r = IOAPIC_INT_BASE;
-
- /* Measure number of APIC timer ticks in 10x 1/hz seconds
- * but calibrate the timer to expire at rate of hz
- * divide by 10 because we waited 10 times longer than we needed */
- calibrated_ticks = pit_measure_10x_apic_hz() / 10;
-
- /* Set up counter later */
- lapic->lvt_timer.r = LAPIC_DISABLE;
-
- /* Install clock interrupt handler on pin 0 */
- ivect[0] = (interrupt_handler_fn)hardclock;
-
printf("IOAPIC 0 configured\n");
}
diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c
index baff8da1..e8462ba3 100644
--- a/i386/i386at/model_dep.c
+++ b/i386/i386at/model_dep.c
@@ -171,7 +171,7 @@ void machine_init(void)
#if defined(APIC)
ioapic_configure();
#endif
- startrtclock();
+ clkstart();
#if defined(APIC)
#warning FIXME: Rather unmask them from their respective drivers
@@ -593,7 +593,11 @@ void
startrtclock(void)
{
#ifdef APIC
- lapic_enable_timer();
+ unmask_irq(timer_pin);
+ calibrate_lapic_timer();
+ if (cpu_number() != 0) {
+ lapic_enable_timer();
+ }
#else
clkstart();
unmask_irq(0);