From 47f37e3b0033dc815719a4a46c9db5a61aceaaff Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Mon, 18 Apr 2011 15:07:45 +0200 Subject: [PATCH] use memory barriers instead of read memory barriers to determine the current TSC => more accurate caclculation of the timer frequency + minor cosmetic changes --- arch/x86/include/asm/processor.h | 2 +- arch/x86/kernel/apic.c | 37 ++++++++++++++++++-------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index a6ed0c13..ce88fcb6 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -140,7 +140,7 @@ static inline void tlb_flush(void) static inline uint32_t read_eflags(void) { uint32_t result; - asm volatile ("pushf; popl %%eax" : "=a"(result) :: "memory"); + asm volatile ("pushf; pop %%eax" : "=a"(result)); return result; } diff --git a/arch/x86/kernel/apic.c b/arch/x86/kernel/apic.c index 151b9143..d35ae989 100644 --- a/arch/x86/kernel/apic.c +++ b/arch/x86/kernel/apic.c @@ -56,6 +56,7 @@ static apic_mp_t* apic_mp = NULL; static apic_config_table_t* apic_config = NULL; static uint32_t lapic = 0; static volatile ioapic_t* ioapic = NULL; +static uint32_t icr = 0; static uint32_t ncores = 1; static uint8_t irq_redirect[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}; #if MAX_CORES > 1 @@ -256,19 +257,28 @@ int smp_init(void) static int lapic_reset(void) { - uint32_t max_lvt = apic_lvt_entries(); + uint32_t max_lvt; + + if (!lapic) + return -ENXIO; + + max_lvt = apic_lvt_entries(); lapic_write(APIC_SVR, 0x17F); // enable the apic and connect to the idt entry 127 lapic_write(APIC_TPR, 0x00); // allow all interrupts - lapic_write(APIC_LVT_T, 0x10000); // disable timer interrupt + if (icr) { + lapic_write(APIC_DCR, 0xB); // set it to 1 clock increments + lapic_write(APIC_LVT_T, 0x2007B); // connects the timer to 123 and enables it + lapic_write(APIC_ICR, icr); + } else + lapic_write(APIC_LVT_T, 0x10000); // disable timer interrupt if (max_lvt >= 4) - lapic_write(APIC_LVT_TSR, 0x10000); // disable thermal sensor interrupt + lapic_write(APIC_LVT_TSR, 0x10000); // disable thermal sensor interrupt if (max_lvt >= 5) - lapic_write(APIC_LVT_PMC, 0x10000); // disable performance counter interrupt + lapic_write(APIC_LVT_PMC, 0x10000); // disable performance counter interrupt lapic_write(APIC_LINT0, 0x7C); // connect LINT0 to idt entry 124 lapic_write(APIC_LINT1, 0x7D); // connect LINT1 to idt entry 125 lapic_write(APIC_LVT_ER, 0x7E); // connect error to idt entry 126 - lapic_write(APIC_ID, 0x00); // reset boot processor id return 0; } @@ -328,13 +338,10 @@ int apic_calibration(void) HALT; diff = 0xFFFFFFFFUL - lapic_read(APIC_CCR); - diff = diff / 3; + icr = diff / 3; flags = irq_nested_disable(); lapic_reset(); - lapic_write(APIC_DCR, 0xB); // set it to 1 clock increments - lapic_write(APIC_LVT_T, 0x2007B); // connects the timer to 123 and enables it - lapic_write(APIC_ICR, diff); irq_nested_enable(flags); // Now, MetalSVM is able to use the APIC => Therefore, we disable the PIC @@ -353,26 +360,23 @@ int apic_calibration(void) lapic_write(APIC_ICR, 0xFFFFFFFFUL); /* wait 3 time slices to determine a ICR */ - rmb(); + mb(); start = rdtsc(); do { - rmb(); + mb(); end = rdtsc(); ticks = end > start ? end - start : start - end; } while(ticks*TIMER_FREQ < 3*RC_REFCLOCKMHZ*1000000UL); diff = 0xFFFFFFFFUL - lapic_read(APIC_CCR); - diff = diff / 3; + icr = diff / 3; lapic_reset(); - lapic_write(APIC_DCR, 0xB); // set it to 1 clock increments - lapic_write(APIC_LVT_T, 0x2007B); // connects the timer to 123 and enables it - lapic_write(APIC_ICR, diff); irq_nested_enable(flags); #endif - kprintf("APIC calibration determines an ICR of 0x%x\n", diff); + kprintf("APIC calibration determines an ICR of 0x%x\n", icr); flags = irq_nested_disable(); #if MAX_CORES > 1 @@ -568,6 +572,7 @@ int apic_init(void) // set APIC error handler irq_install_handler(126, apic_err_handler); + // initialize local apic ret = lapic_reset(); if (!ret) return ret;