x86: changes LAPIC timer divisor to 32
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 19 Mar 2013 00:25:44 +0000 (17:25 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 19 Mar 2013 01:22:32 +0000 (18:22 -0700)
Seems like a reasonable choice.  128 wasn't working on c89, since the
bus was so slow (100MHz) that we couldn't express 1 usec.  We could
allow some runtime setting/resetting, but 32 should be fine for anything
we need.

kern/arch/i686/apic.c
kern/arch/i686/apic.h
kern/arch/i686/cpuinfo.c
kern/arch/i686/x86.h

index 8523c69..c20b237 100644 (file)
@@ -155,11 +155,11 @@ void __lapic_set_timer(uint32_t ticks, uint8_t vec, bool periodic, uint8_t div)
 
 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;
+       uint32_t ticks = (usec * system_timing.bus_freq / LAPIC_TIMER_DIVISOR_VAL)
+                        / 1000000;
        assert(ticks > 0);
        __lapic_set_timer(ticks, LAPIC_TIMER_DEFAULT_VECTOR, periodic,
-                         LAPIC_TIMER_DEFAULT_DIVISOR);
+                         LAPIC_TIMER_DIVISOR_BITS);
 }
 
 void set_core_timer(uint32_t usec, bool periodic)
@@ -188,18 +188,20 @@ void timer_init(void){
        udelay_pit(1000000);
        tscval[1] = read_tsc();
        system_timing.tsc_freq = SINIT(tscval[1] - tscval[0]);
-       
        cprintf("TSC Frequency: %llu\n", system_timing.tsc_freq);
-
        __lapic_set_timer(0xffffffff, LAPIC_TIMER_DEFAULT_VECTOR, FALSE,
-                         LAPIC_TIMER_DEFAULT_DIVISOR);
+                         LAPIC_TIMER_DIVISOR_BITS);
        // 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 = SINIT((timercount[0] - timercount[1])*128);
-               
+       system_timing.bus_freq = (timercount[0] - timercount[1])
+                                * LAPIC_TIMER_DIVISOR_VAL;
+       /* The time base for the timer is derived from the processor's bus clock,
+        * divided by the value specified in the divide configuration register.
+        * Note we mult and div by the divisor, saving the actual freq (even though
+        * we don't use it yet). */
        cprintf("Bus Frequency: %llu\n", system_timing.bus_freq);
 }
 
index 943bd42..47dec11 100644 (file)
 #define LAPIC_TIMER_CURRENT                    (LAPIC_BASE + 0x390)
 #define LAPIC_TIMER_DIVIDE                     (LAPIC_BASE + 0x3e0)
 #define LAPIC_TIMER_DEFAULT_VECTOR     0xeb            /* Aka 235, IRQ203 */
-#define LAPIC_TIMER_DEFAULT_DIVISOR    0xa // This is 128.  Ref SDM 3.a 9.6.4
+/* Quick note on the divisor.  The LAPIC timer ticks once per divisor-bus ticks
+ * (system bus or APIC bus, depending on the model).  Ex: A divisor of 128 means
+ * 128 bus ticks results in 1 timer tick.  The divisor increases the time range
+ * and decreases the granularity of the timer.  Numbers are appx, based on 4
+ * billion ticks, vs 2^32 ticks.
+ * Ex:   1GHz bus, div 001:    4sec max,    1ns granularity
+ * Ex:   1GHz bus, div 128:  512sec max,  128ns granularity
+ * Ex: 100MHz bus, div 001:   40sec max,   10ns granularity
+ * Ex: 100MHz bus, div 128: 5120sec max, 1280ns granularity */
+#define LAPIC_TIMER_DIVISOR_VAL                32      /* seems reasonable */
+#define LAPIC_TIMER_DIVISOR_BITS       0x8     /* Div = 32 */
+
 // IPI Interrupt Command Register
 #define LAPIC_IPI_ICR_LOWER                    (LAPIC_BASE + 0x300)
 #define LAPIC_IPI_ICR_UPPER                    (LAPIC_BASE + 0x310)
index 6404541..60cddec 100644 (file)
@@ -133,7 +133,15 @@ void print_cpuinfo(void)
                printk("RDTSCP supported\n");
        else
                printk("RDTSCP not supported: don't trust detailed measurements\n");
-
+       msr_val = read_msr(IA32_MISC_ENABLE);
+       /* we want this to be not set for cpuid.6h to work. */
+       if (msr_val & (1 << 22))
+               write_msr(IA32_MISC_ENABLE, msr_val & ~(1 << 22));
+       cpuid(0x00000006, 0x0, &eax, 0, 0, 0);
+       if (eax & (1 << 2))
+               printk("Always running APIC detected\n");
+       else
+               printk("Always running APIC *not* detected\n");
 }
 
 void show_mapping(uintptr_t start, size_t size)
index 84f0c57..493df85 100644 (file)
@@ -7,6 +7,8 @@
 /* Model Specific Registers */
 #define IA32_APIC_BASE                         0x1b
 #define IA32_FEATURE_CONTROL           0x3a
+#define IA32_MISC_ENABLE                       0x1a0
+
 #define IA32_MTRR_DEF_TYPE                     0x2ff
 #define IA32_MTRR_PHYSBASE0                    0x200
 #define IA32_MTRR_PHYSMASK0                    0x201