Subversion Repositories shark

Compare Revisions

Ignore whitespace Rev 304 → Rev 305

/shark/trunk/oslib/kl/advtimer.c
25,145 → 25,30
 
#include <ll/i386/stdlib.h>
#include <ll/i386/error.h>
#include <ll/i386/advtimer.h>
#include <ll/sys/ll/ll-data.h>
#include <ll/sys/ll/ll-func.h>
#include <ll/i386/pic.h>
#include <ll/i386/apic.h>
#include <ll/i386/64bit.h>
#include <ll/sys/ll/event.h>
#include <ll/sys/ll/time.h>
#include <ll/i386/advtimer.h>
 
#define CALIBRATE_USING_CMOS
 
unsigned char use_tsc = 1; //Enable the TSC counter mode
unsigned char use_cmos = 0; //Enable the RTC correction
unsigned char use_apic = 0; //Enable the APIC for P6 only
unsigned long long init_tsc;
unsigned long long * ptr_init_tsc = &init_tsc;
 
//Max single delta_clk_per_msec increment = clk_per_msec / MAX_DIV_INK;
#define MAX_DIV_INK 30000
unsigned long long init_nsec; //Wraparound 292 years
unsigned long long * ptr_init_nsec = &init_nsec;
 
signed long long init_tsc;
signed long long * ptr_init_tsc = &init_tsc;
unsigned int clk_per_msec = 0;
unsigned int apic_clk_per_msec = 0;
unsigned int apic_set_limit = 0;
 
signed long long init_nsec; //Wraparound 292 years
signed long long * ptr_init_nsec = &init_nsec;
 
signed long long clk_per_msec;
signed long long * ptr_clk_per_msec = &clk_per_msec;
 
signed long long apic_clk_per_msec;
unsigned int apic_set_limit;
 
signed long last_delta_clk_per_msec;
signed long total_delta_clk_per_msec;
 
unsigned char save_CMOS_regA;
unsigned char save_CMOS_regB;
 
//#define IRQ8_DEBUG
 
void HandlerIRQ8(void *p)
{
 
unsigned char set;
 
static unsigned long Mconst = 1000000;
static unsigned long init_step = 0;
signed long max_dcms = clk_per_msec / MAX_DIV_INK;
static signed long long dn;
static signed long long * ptr_dn = &dn;
signed long delta_clk_per_msec;
cli();
 
#ifdef IRQ8_DEBUG
message("(IRQ8");
#endif
 
CMOS_READ(0x0C,set);
 
__asm__("xorl %%eax,%%eax\n\t"
"cpuid\n\t"
"rdtsc\n\t"
"pushl %%eax\n\t"
"pushl %%edx\n\t"
"pushl %%eax\n\t"
"pushl %%edx\n\t"
"xorl %%eax,%%eax\n\t"
"cpuid\n\t"
"popl %%edx\n\t"
"popl %%eax\n\t"
"subl (%%edi),%%eax\n\t"
"sbbl 4(%%edi),%%edx\n\t"
"popl 4(%%edi)\n\t"
"popl (%%edi)\n\t"
"movl %%edx,%%ecx\n\t"
"mull %4\n\t"
"pushl %%eax\n\t"
"movl %%ecx,%%eax\n\t"
"movl %%edx,%%ecx\n\t"
"mull %4\n\t"
"addl %%ecx,%%eax\n\t"
"adcl $0,%%edx\n\t"
"movl %7,%%ebx\n\t"
"divl (%%ebx)\n\t"
"movl %%eax,4(%%esi)\n\t"
"popl %%eax\n\t"
"divl (%%ebx)\n\t"
"movl %%eax,(%%esi)\n\t"
:
: "D" (ptr_init_tsc), "S" (ptr_dn), "b" (0),
"c" (0), "m" (Mconst), "a" (0), "d" (0), "m" (ptr_clk_per_msec));
//Offset
init_nsec += dn;
 
if (init_step < 5) {
init_step++;
#ifdef IRQ8_DEBUG
message(")");
#endif
 
sti();
 
return;
}
dn = dn % 1000000000 - 500000000;
//Delta clk/msec
delta_clk_per_msec = dn * clk_per_msec / (500000000 - dn);
//clk_per_msec adjustment
if (delta_clk_per_msec < 0) {
if (delta_clk_per_msec > -max_dcms)
clk_per_msec += delta_clk_per_msec;
else
clk_per_msec -= max_dcms;
} else {
if (delta_clk_per_msec < max_dcms)
clk_per_msec += delta_clk_per_msec;
else
clk_per_msec += max_dcms;
}
last_delta_clk_per_msec = delta_clk_per_msec;
total_delta_clk_per_msec += delta_clk_per_msec;
#ifdef IRQ8_DEBUG
message(")");
#endif
 
sti();
}
 
#ifdef CONFIG_MELAN
# define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
#else
178,11 → 63,11
void ll_calibrate_tsc(void)
{
 
signed long long start;
signed long long end;
signed long long dtsc;
unsigned long long start;
unsigned long long end;
unsigned long long dtsc;
signed long start_8253, end_8253, delta_8253;
unsigned int start_8253, end_8253, delta_8253;
 
cli();
231,13 → 116,13
ll_abort(10);
}
 
message("Delta TSC = %10ld\n",(long)dtsc);
message("Delta TSC = %10d\n",(int)dtsc);
 
message("Delta PIT = %10ld\n",(long)delta_8253);
message("Delta PIT = %10d\n",delta_8253);
 
clk_per_msec = dtsc * CLOCK_TICK_RATE / delta_8253 / 1000;
message("Calibrated Clk_per_msec = %10ld\n",(long)clk_per_msec);
message("Calibrated Clk_per_msec = %10d\n",clk_per_msec);
 
sti();
249,8 → 134,8
#define CMOS_END 3
 
int cmos_calibrate_status = CMOS_INIT;
signed long long irq8_start;
signed long long irq8_end;
unsigned long long irq8_start;
unsigned long long irq8_end;
 
void calibrate_tsc_IRQ8(void *p)
{
286,7 → 171,7
void ll_calibrate_tsc_cmos(void)
{
 
signed long long dtsc;
unsigned long long dtsc;
 
cli();
310,7 → 195,7
 
clk_per_msec = dtsc / 500;
 
message("Calibrated CPU Clk/msec = %10ld\n",(long)clk_per_msec);
message("Calibrated CPU Clk/msec = %10d\n",clk_per_msec);
 
cli();
 
323,53 → 208,6
 
}
 
//Low level time read function
void ll_read_timespec(struct timespec *tspec)
{
 
static unsigned long Gconst = 1000000000;
static unsigned long Mconst = 1000000;
 
if (clk_per_msec <= 0) {
NULL_TIMESPEC(tspec);
return;
}
__asm__("xorl %%eax,%%eax\n\t"
"cpuid\n\t"
"rdtsc\n\t"
"pushl %%eax\n\t"
"pushl %%edx\n\t"
"xorl %%eax,%%eax\n\t"
"cpuid\n\t"
"popl %%edx\n\t"
"popl %%eax\n\t"
"subl (%%edi),%%eax\n\t"
"sbbl 4(%%edi),%%edx\n\t"
"movl %%edx,%%ecx\n\t"
"mull %6\n\t"
"pushl %%eax\n\t"
"movl %%ecx,%%eax\n\t"
"movl %%edx,%%ecx\n\t"
"mull %6\n\t"
"addl %%ecx,%%eax\n\t"
"adcl $0,%%edx\n\t"
"movl %8,%%ebx\n\t"
"divl (%%ebx)\n\t"
"movl %%eax,%%ecx\n\t"
"popl %%eax\n\t"
"divl (%%ebx)\n\t"
"movl %%ecx,%%edx\n\t"
"addl (%%esi),%%eax\n\t"
"adcl 4(%%esi),%%edx\n\t"
"divl %7\n\t"
: "=a" (tspec->tv_sec), "=d" (tspec->tv_nsec)
: "D" (ptr_init_tsc), "S" (ptr_init_nsec), "b" (0),
"c" (0), "m" (Mconst), "m" (Gconst), "m" (ptr_clk_per_msec));
}
 
int apic_get_maxlvt(void)
{
unsigned int v, ver, maxlvt;
523,7 → 361,7
{
 
unsigned int apic_start = 0, apic_end = 0, dapic;
signed long long tsc_start = 0, tsc_end = 0, dtsc;
unsigned long long tsc_start = 0, tsc_end = 0, dtsc;
unsigned int tmp_value;
 
cli();
557,17 → 395,20
dtsc = tsc_end - tsc_start;
dapic = apic_start - apic_end;
 
apic_clk_per_msec = clk_per_msec * (signed long long)(dapic) / dtsc;
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 = %10ld\n",(long)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
 
if (use_tsc) {
#ifdef __TSC__
#ifdef CALIBRATE_USING_CMOS
ll_calibrate_tsc_cmos();
575,14 → 416,10
ll_calibrate_tsc();
#endif
 
last_delta_clk_per_msec = 0;
total_delta_clk_per_msec = 0;
rdtscll(init_tsc); // Read start TSC
init_nsec = 0;
 
if (use_apic) {
unsigned long msr_low_orig, tmp;
#ifdef __APIC__
 
rdmsr(APIC_BASE_MSR, msr_low_orig, tmp);
wrmsr(APIC_BASE_MSR, msr_low_orig|(1<<11), 0);
595,53 → 432,17
setup_APIC_timer();
 
}
#endif
 
if (use_cmos) {
#endif
 
message("CMOS adjustement enabled\n");
cli();
irq_bind(8, HandlerIRQ8, 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
 
irq_unmask(8);
 
sti();
}
 
} else {
 
use_cmos = 0;
 
}
 
}
 
void ll_restore_adv()
{
/* Restore CMOS setting */
if (use_cmos) {
cli();
irq_mask(8);
CMOS_WRITE(0x0A,save_CMOS_regA);
CMOS_WRITE(0x0B,save_CMOS_regB);
sti();
}
 
/* Disable APIC */
if (use_apic) {
unsigned int msr_low_orig, tmp;
#ifdef __APIC__
unsigned int msr_low_orig, tmp;
 
cli();
 
652,6 → 453,6
 
sti();
 
}
#endif
}