58,6 → 58,11 |
unsigned char save_CMOS_regA; |
unsigned char save_CMOS_regB; |
|
unsigned char X86_tsc = 0; |
unsigned char X86_apic = 0; |
unsigned char use_tsc = 0; |
unsigned char use_apic = 0; |
|
#ifdef CONFIG_MELAN |
# define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */ |
#else |
84,36 → 89,34 |
outp(0x42,0xFF); /* LSB of count */ |
outp(0x42,0xFF); /* MSB of count */ |
|
barrier(); |
rdtscll(start); |
barrier(); |
outp(0x43,0x00); |
barrier(); |
rdtscll(start); |
barrier(); |
outp(0x43,0x00); |
start_8253 = inp(0x42); |
start_8253 |= inp(0x42) << 8; |
barrier(); |
rdtscll(start); |
barrier(); |
barrier(); |
rdtscll(start); |
barrier(); |
|
do { |
|
outp(0x43,0x00); |
end_8253 = inp(0x42); |
end_8253 |= inp(0x42) << 8; |
|
} while (end_8253 > COUNTER_END); |
|
barrier(); |
rdtscll(end); |
barrier(); |
barrier(); |
rdtscll(end); |
barrier(); |
outp(0x43,0x00); |
end_8253 = inp(0x42); |
end_8253 |= inp(0x42) << 8; |
barrier(); |
rdtscll(end); |
barrier(); |
barrier(); |
rdtscll(end); |
barrier(); |
|
//Delta TSC |
dtsc = end - start; |
dtsc = end - start; |
|
//Delta PIT |
delta_8253 = start_8253 - end_8253; |
130,7 → 133,6 |
clk_per_msec = dtsc * CLOCK_TICK_RATE / delta_8253 / 1000; |
|
message("Calibrated Clk_per_msec = %10d\n",clk_per_msec); |
|
} |
|
#define CMOS_INIT 0 |
144,98 → 146,94 |
|
void calibrate_tsc_IRQ8(void *p) |
{ |
unsigned char set; |
|
unsigned char set; |
CMOS_READ(0x0C,set); |
|
CMOS_READ(0x0C,set); |
barrier(); |
rdtscll(irq8_end); |
barrier(); |
|
barrier(); |
rdtscll(irq8_end); |
barrier(); |
if (cmos_calibrate_status == CMOS_START) { |
cmos_calibrate_status = CMOS_END; |
} |
|
if (cmos_calibrate_status == CMOS_START) { |
cmos_calibrate_status = CMOS_END; |
} |
if (cmos_calibrate_status == CMOS_BEGIN) { |
irq8_start = irq8_end; |
cmos_calibrate_status = CMOS_START; |
} |
|
if (cmos_calibrate_status == CMOS_BEGIN) { |
irq8_start = irq8_end; |
cmos_calibrate_status = CMOS_START; |
} |
|
if (cmos_calibrate_status == CMOS_INIT) { |
cmos_calibrate_status = CMOS_BEGIN; |
} |
|
if (cmos_calibrate_status == CMOS_INIT) { |
cmos_calibrate_status = CMOS_BEGIN; |
} |
} |
|
//TSC Calibration using RTC |
void ll_calibrate_tsc_cmos(void) |
{ |
unsigned long long dtsc; |
|
unsigned long long dtsc; |
irq_bind(8, calibrate_tsc_IRQ8, INT_FORCE); |
|
irq_bind(8, calibrate_tsc_IRQ8, INT_FORCE); |
CMOS_READ(0x0A,save_CMOS_regA); |
CMOS_READ(0x0B,save_CMOS_regB); |
|
CMOS_WRITE(0x0A,0x2F); // Set 2 Hz Periodic Interrupt |
CMOS_WRITE(0x0B,0x42); // Enable Interrupt |
|
CMOS_READ(0x0A,save_CMOS_regA); |
CMOS_READ(0x0B,save_CMOS_regB); |
|
CMOS_WRITE(0x0A,0x2F); // Set 2 Hz Periodic Interrupt |
CMOS_WRITE(0x0B,0x42); // Enable Interrupt |
|
irq_unmask(8); |
irq_unmask(8); |
|
sti(); |
sti(); |
|
while (cmos_calibrate_status != CMOS_END) { |
barrier(); |
} |
while (cmos_calibrate_status != CMOS_END) { |
barrier(); |
} |
|
cli(); |
cli(); |
|
dtsc = irq8_end - irq8_start; |
dtsc = irq8_end - irq8_start; |
|
clk_per_msec = dtsc / 500; |
clk_opt_0 = (unsigned int)(dtsc); |
clk_opt_1 = (unsigned int)((unsigned long long)(dtsc << 1)); |
clk_opt_2 = (unsigned int)((unsigned long long)(dtsc << 33) / 1000000000L); |
clk_opt_3 = (unsigned int)((unsigned long long)(dtsc << 32) / 1000000000L); |
clk_opt_4 = (unsigned int)((unsigned long long)(dtsc << 31) / 1000000000L); |
clk_opt_5 = (unsigned int)((unsigned long long)(dtsc << 30) / 1000000000L); |
clk_per_msec = dtsc / 500; |
clk_opt_0 = (unsigned int)(dtsc); |
clk_opt_1 = (unsigned int)((unsigned long long)(dtsc << 1)); |
clk_opt_2 = (unsigned int)((unsigned long long)(dtsc << 33) / 1000000000L); |
clk_opt_3 = (unsigned int)((unsigned long long)(dtsc << 32) / 1000000000L); |
clk_opt_4 = (unsigned int)((unsigned long long)(dtsc << 31) / 1000000000L); |
clk_opt_5 = (unsigned int)((unsigned long long)(dtsc << 30) / 1000000000L); |
|
message("Calibrated CPU Clk/msec = %10u\n",clk_per_msec); |
message("Calibrated CPU Clk/msec = %10u\n",clk_per_msec); |
|
#ifdef __O1000__ |
if (clk_per_msec < 1000000) { |
message("Timer Optimization CPU < 1 GHz\n"); |
} else { |
message("Bad Timer Optimization\n"); |
ll_abort(66); |
} |
#endif |
#ifdef __O1000__ |
if (clk_per_msec < 1000000) { |
message("Timer Optimization CPU < 1 GHz\n"); |
} else { |
message("Bad Timer Optimization\n"); |
ll_abort(66); |
} |
#endif |
|
#ifdef __O2000__ |
if (clk_per_msec < 2000000 && clk_per_msec >= 1000000) { |
message("Timer Optimization 1 GHz < CPU < 2 GHz\n"); |
} else { |
message("Bad Timer Optimization\n"); |
ll_abort(66); |
} |
#endif |
#ifdef __O2000__ |
if (clk_per_msec < 2000000 && clk_per_msec >= 1000000) { |
message("Timer Optimization 1 GHz < CPU < 2 GHz\n"); |
} else { |
message("Bad Timer Optimization\n"); |
ll_abort(66); |
} |
#endif |
|
#ifdef __O4000__ |
if (clk_per_msec < 4000000 && clk_per_msec >= 2000000) { |
message("Timer Optimization 2 GHz < CPU < 4 GHz\n"); |
} else { |
message("Bad Timer Optimization\n"); |
ll_abort(66); |
} |
#endif |
#ifdef __O4000__ |
if (clk_per_msec < 4000000 && clk_per_msec >= 2000000) { |
message("Timer Optimization 2 GHz < CPU < 4 GHz\n"); |
} else { |
message("Bad Timer Optimization\n"); |
ll_abort(66); |
} |
#endif |
|
irq_mask(8); |
irq_mask(8); |
|
CMOS_WRITE(0x0A,save_CMOS_regA); |
CMOS_WRITE(0x0B,save_CMOS_regB); |
|
CMOS_WRITE(0x0A,save_CMOS_regA); |
CMOS_WRITE(0x0B,save_CMOS_regB); |
} |
|
int apic_get_maxlvt(void) |
323,41 → 321,38 |
unsigned long value; |
|
/* Pound the ESR really hard over the head with a big hammer - mbligh */ |
|
|
apic_write(APIC_ESR, 0); |
apic_write(APIC_ESR, 0); |
apic_write(APIC_ESR, 0); |
apic_write(APIC_ESR, 0); |
|
|
value = APIC_SPIV_FOCUS_DISABLED | APIC_SPIV_APIC_ENABLED | SPURIOUS_APIC_VECTOR; |
apic_write_around(APIC_SPIV, value); |
|
value = APIC_DM_EXTINT | APIC_LVT_LEVEL_TRIGGER; |
apic_write_around(APIC_LVT0, value); |
value = APIC_DM_EXTINT | APIC_LVT_LEVEL_TRIGGER; |
apic_write_around(APIC_LVT0, value); |
|
value = APIC_DM_NMI; |
apic_write_around(APIC_LVT1, value); |
value = APIC_DM_NMI; |
apic_write_around(APIC_LVT1, value); |
|
apic_write(APIC_ESR, 0); |
|
apic_write(APIC_ESR, 0); |
} |
|
void disable_APIC_timer(void) |
{ |
unsigned long v; |
unsigned long v; |
|
v = apic_read(APIC_LVTT); |
apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED); |
|
v = apic_read(APIC_LVTT); |
apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED); |
} |
|
void enable_APIC_timer(void) |
{ |
unsigned long v; |
unsigned long v; |
|
v = apic_read(APIC_LVTT); |
apic_write_around(APIC_LVTT, v & ~APIC_LVT_MASKED); |
|
v = apic_read(APIC_LVTT); |
apic_write_around(APIC_LVTT, v & ~APIC_LVT_MASKED); |
} |
|
#define LOCAL_TIMER_VECTOR 0x39 |
365,20 → 360,20 |
/* Set APIC Timer... from Linux kernel */ |
void setup_APIC_timer() |
{ |
unsigned int lvtt1_value; |
|
lvtt1_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | |
APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR; |
apic_write_around(APIC_LVTT, lvtt1_value); |
|
/* |
* Divide PICLK by 1 |
*/ |
apic_write_around(APIC_TDCR, APIC_TDR_DIV_1); |
unsigned int lvtt1_value; |
|
apic_write_around(APIC_TMICT, MAX_DWORD); |
lvtt1_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | |
APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR; |
apic_write_around(APIC_LVTT, lvtt1_value); |
|
disable_APIC_timer(); |
/* |
* Divide PICLK by 1 |
*/ |
apic_write_around(APIC_TDCR, APIC_TDR_DIV_1); |
|
apic_write_around(APIC_TMICT, MAX_DWORD); |
|
disable_APIC_timer(); |
} |
|
#define APIC_LIMIT 0xFF000000 |
386,89 → 381,89 |
|
void ll_calibrate_apic(void) |
{ |
unsigned int apic_start = 0, apic_end = 0, dapic; |
unsigned long long tsc_start = 0, tsc_end = 0, dtsc; |
unsigned int tmp_value; |
|
unsigned int apic_start = 0, apic_end = 0, dapic; |
unsigned long long tsc_start = 0, tsc_end = 0, dtsc; |
unsigned int tmp_value; |
tmp_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | LOCAL_TIMER_VECTOR; |
apic_write_around(APIC_LVTT, tmp_value); |
|
tmp_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | LOCAL_TIMER_VECTOR; |
apic_write_around(APIC_LVTT, tmp_value); |
apic_write_around(APIC_TDCR, APIC_TDR_DIV_1); |
|
apic_write_around(APIC_TDCR, APIC_TDR_DIV_1); |
apic_write(APIC_TMICT, MAX_DWORD); |
|
apic_write(APIC_TMICT, MAX_DWORD); |
enable_APIC_timer(); |
|
enable_APIC_timer(); |
barrier(); |
rdtscll(tsc_start); |
barrier(); |
apic_start = apic_read(APIC_TMCCT); |
barrier(); |
|
barrier(); |
rdtscll(tsc_start); |
barrier(); |
apic_start = apic_read(APIC_TMCCT); |
barrier(); |
|
while (apic_read(APIC_TMCCT) > APIC_LIMIT) { |
barrier(); |
rdtscll(tsc_end); |
} |
while (apic_read(APIC_TMCCT) > APIC_LIMIT) { |
barrier(); |
rdtscll(tsc_end); |
} |
|
barrier(); |
rdtscll(tsc_end); |
barrier(); |
apic_end = apic_read(APIC_TMCCT); |
barrier(); |
barrier(); |
rdtscll(tsc_end); |
barrier(); |
apic_end = apic_read(APIC_TMCCT); |
barrier(); |
|
disable_APIC_timer(); |
disable_APIC_timer(); |
|
dtsc = tsc_end - tsc_start; |
dapic = apic_start - apic_end; |
dtsc = tsc_end - tsc_start; |
dapic = apic_start - apic_end; |
|
apic_clk_per_msec = (unsigned long long)(clk_per_msec) * (unsigned long long)(dapic) / dtsc; |
apic_set_limit = ((apic_clk_per_msec / 100) != 0) ? (apic_clk_per_msec/100) : APIC_SET_LIMIT; |
|
apic_clk_per_msec = (unsigned long long)(clk_per_msec) * (unsigned long long)(dapic) / dtsc; |
apic_set_limit = ((apic_clk_per_msec / 100) != 0) ? (apic_clk_per_msec/100) : APIC_SET_LIMIT; |
|
message("Calibrated APIC Clk/msec = %10d\n",apic_clk_per_msec); |
|
message("Calibrated APIC Clk/msec = %10d\n",apic_clk_per_msec); |
} |
|
void ll_init_advtimer() |
{ |
#ifdef __APIC__ |
unsigned long msr_low_orig, tmp; |
#endif |
unsigned long msr_low_orig, tmp; |
|
#ifdef __TSC__ |
#ifdef __APIC__ |
use_apic = X86_apic; |
#endif |
|
#ifdef __TSC__ |
use_tsc = X86_tsc; |
#endif |
|
if (use_tsc) { |
|
#ifdef CALIBRATE_USING_CMOS |
ll_calibrate_tsc_cmos(); |
#else |
ll_calibrate_tsc(); |
#endif |
#ifdef CALIBRATE_USING_CMOS |
ll_calibrate_tsc_cmos(); |
#else |
ll_calibrate_tsc(); |
#endif |
|
rdtscll(init_tsc); // Read start TSC |
init_nsec = 0; |
rdtscll(init_tsc); // Read start TSC |
init_nsec = 0; |
|
#ifdef __APIC__ |
if (use_apic) { |
rdmsr(APIC_BASE_MSR, msr_low_orig, tmp); |
wrmsr(APIC_BASE_MSR, msr_low_orig|(1<<11), 0); |
|
rdmsr(APIC_BASE_MSR, msr_low_orig, tmp); |
wrmsr(APIC_BASE_MSR, msr_low_orig|(1<<11), 0); |
clear_local_APIC(); |
|
clear_local_APIC(); |
ll_calibrate_apic(); |
|
ll_calibrate_apic(); |
|
setup_local_APIC(); |
setup_local_APIC(); |
|
setup_APIC_timer(); |
|
#endif |
|
#endif |
|
setup_APIC_timer(); |
} |
} |
} |
|
void ll_restore_adv() |
{ |
/* Disable APIC */ |
#ifdef __APIC__ |
if (use_apic) { |
unsigned int msr_low_orig, tmp; |
|
cli(); |
479,7 → 474,5 |
wrmsr(APIC_BASE_MSR, msr_low_orig&~(1<<11), 0); |
|
sti(); |
|
#endif |
|
} |
} |