LAPIC Timer work
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 21 May 2009 00:44:40 +0000 (17:44 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 21 May 2009 00:44:40 +0000 (17:44 -0700)
Adds a wrapper to set up the LAPIC Timer in usec, instead of ticks.
Also tweaks some of the training and testing to avoid extra interrupts.

kern/apic.c
kern/apic.h
kern/testing.c

index aae2291..2d2bcad 100644 (file)
@@ -58,20 +58,16 @@ void pic_unmask_irq(uint8_t irq)
 
 /*
  * Sets the LAPIC timer to go off after a certain number of ticks.  The primary
- * clock freq is actually the bus clock, so we really will need to figure out
- * the timing of the LAPIC timer via other timing.  For now, set it to a
- * certain number of ticks, and specify an interrupt vector to send to the CPU.
+ * clock freq is actually the bus clock, which we figure out during timer_init
  * Unmasking is implied.  Ref SDM, 3A, 9.6.4
  */
-void lapic_set_timer(uint32_t ticks, uint8_t vector, bool periodic)
+void __lapic_set_timer(uint32_t ticks, uint8_t vec, bool periodic, uint8_t div)
 {
-       //needs to read LAPIC_TIMER_DIVIDE before writing
-       uint32_t orig_divider = read_mmreg32(LAPIC_TIMER_DIVIDE);
-       // divide the bus clock.  going with the max (128) for now (which is slow)
-       // clears bottom bit and then set divider to be 128
-       write_mmreg32(LAPIC_TIMER_DIVIDE, (orig_divider & ~0x1111) | 0xa);
+       // clears bottom bit and then set divider
+       write_mmreg32(LAPIC_TIMER_DIVIDE, (read_mmreg32(LAPIC_TIMER_DIVIDE) &~0xf) |
+                     (div & 0xf));
        // set LVT with interrupt handling information
-       write_mmreg32(LAPIC_LVT_TIMER, vector | (periodic << 17));
+       write_mmreg32(LAPIC_LVT_TIMER, vec | (periodic << 17));
        write_mmreg32(LAPIC_TIMER_INIT, ticks);
        // For debugging when we expand this
        //cprintf("LAPIC LVT Timer: 0x%08x\n", read_mmreg32(LAPIC_LVT_TIMER));
@@ -79,6 +75,14 @@ void lapic_set_timer(uint32_t ticks, uint8_t vector, bool periodic)
        //cprintf("LAPIC Current Count: 0x%08x\n", read_mmreg32(LAPIC_TIMER_CURRENT));
 }
 
+void lapic_set_timer(uint32_t usec, bool periodic)
+{
+       // divide the bus clock by 128, which is the max.
+       uint32_t ticks = (usec * system_timing.bus_freq / 128) / 1000000;
+       __lapic_set_timer(ticks, LAPIC_TIMER_DEFAULT_VECTOR, periodic,
+                         LAPIC_TIMER_DEFAULT_DIVISOR);
+}
+
 uint32_t lapic_get_default_id(void)
 {
        uint32_t ebx;
@@ -99,15 +103,17 @@ void timer_init(void){
        system_timing.tsc_freq = tscval[1] - tscval[0];
        
        cprintf("TSC Frequency: %llu\n", system_timing.tsc_freq);
-       
-       lapic_set_timer(1000000000,0xeb, TRUE);
+
+       __lapic_set_timer(0xffffffff, LAPIC_TIMER_DEFAULT_VECTOR, FALSE,
+                         LAPIC_TIMER_DEFAULT_DIVISOR);
+       // Mask the LAPIC Timer, so we never receive this interrupt (minor race)
+       mask_lapic_lvt(LAPIC_LVT_TIMER);
        timercount[0] = read_mmreg32(LAPIC_TIMER_CURRENT);
        udelay_pit(1000000);
        timercount[1] = read_mmreg32(LAPIC_TIMER_CURRENT);
        system_timing.bus_freq = (timercount[0] - timercount[1])*128;
                
        cprintf("Bus Frequency: %llu\n", system_timing.bus_freq);
-       
 }
 
 void pit_set_timer(uint32_t divisor, uint32_t mode)
index a7c7c8c..fa66cd3 100644 (file)
@@ -44,6 +44,8 @@
 #define LAPIC_TIMER_INIT                       (LAPIC_BASE + 0x380)
 #define LAPIC_TIMER_CURRENT                    (LAPIC_BASE + 0x390)
 #define LAPIC_TIMER_DIVIDE                     (LAPIC_BASE + 0x3e0)
+#define LAPIC_TIMER_DEFAULT_VECTOR     0xeb
+#define LAPIC_TIMER_DEFAULT_DIVISOR    0xa // This is 128.  Ref SDM 3.a 9.6.4
 // IPI Interrupt Command Register
 #define LAPIC_IPI_ICR_LOWER                    (LAPIC_BASE + 0x300)
 #define LAPIC_IPI_ICR_UPPER                    (LAPIC_BASE + 0x310)
@@ -91,21 +93,18 @@ extern system_timing_t system_timing;
 void pic_remap(void);
 void pic_mask_irq(uint8_t irq);
 void pic_unmask_irq(uint8_t irq);
-void lapic_set_timer(uint32_t ticks, uint8_t vector, bool periodic);
+void __lapic_set_timer(uint32_t ticks, uint8_t vec, bool periodic, uint8_t div);
+void lapic_set_timer(uint32_t usec, bool periodic);
 uint32_t lapic_get_default_id(void);
 // PIT related
 void pit_set_timer(uint32_t freq, uint32_t mode);
 void timer_init(void);
 void udelay(uint64_t usec);
+void udelay_pit(uint64_t usec);
 // TODO: right now timer defaults to TSC
 uint64_t gettimer(void);
 uint64_t inline getfreq(void);
 
-
-static int getpit(void);
-static inline void udelay_pit(uint64_t usec);
-
-
 static inline void pic_send_eoi(uint32_t irq);
 static inline void lapic_send_eoi(void);
 static inline uint32_t lapic_get_version(void);
index 10cf601..f57c218 100644 (file)
@@ -462,7 +462,7 @@ static void test_waiting_handler(trapframe_t *tf, void* data)
 void test_pit(void)
 {
        cprintf("Starting test for PIT now (10s)\n");
-       udelay(10000000);
+       udelay_pit(10000000);
        cprintf("End now\n");
        cprintf("Starting test for TSC (if stable) now (10s)\n");
        udelay(10000000);
@@ -470,7 +470,7 @@ void test_pit(void)
        
        cprintf("Starting test for LAPIC (if stable) now (10s)\n");
        enable_irq();
-       lapic_set_timer(10* system_timing.bus_freq/128, test_vector, TRUE);
+       lapic_set_timer(10000000, FALSE);
        
        uint32_t waiting = 1;
        register_interrupt_handler(interrupt_handlers, test_vector,