X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=blobdiff_plain;f=palacios%2Fsrc%2Fgeekos%2Ftimer.c;h=e0311a42577e27b8945f95abc8a83aad2ef992f2;hp=113a17f3435041baafa75eac360dbbac2a5606fd;hb=d8fc6aa4bc2a5d9cec50923e9d2bd30f867dd50a;hpb=639fdba00d36b2a60fad3d28703459354cf8744f diff --git a/palacios/src/geekos/timer.c b/palacios/src/geekos/timer.c index 113a17f..e0311a4 100644 --- a/palacios/src/geekos/timer.c +++ b/palacios/src/geekos/timer.c @@ -2,7 +2,7 @@ * GeekOS timer interrupt support * Copyright (c) 2001,2003 David H. Hovemeyer * Copyright (c) 2003, Jeffrey K. Hollingsworth - * $Revision: 1.3 $ + * $Revision: 1.4 $ * * This is free software. You are permitted to use, * redistribute, and modify it as specified in the file "COPYING". @@ -18,7 +18,142 @@ #include #include -#define HZ 100 + +/* JRL Add a cpu frequency measurement */ +uint_t cpu_khz_freq; + + +#define __SLOW_DOWN_IO "\noutb %%al,$0x80" + +#ifdef REALLY_SLOW_IO +#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO +#else +#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO +#endif + + + +#define __OUT1(s,x) \ +static inline void out##s(unsigned x value, unsigned short port) { + +#define __OUT2(s,s1,s2) \ +__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" + +#define __OUT(s,s1,x) \ +__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \ +__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \ + + +#define __IN1(s) \ +static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v; + +#define __IN2(s,s1,s2) \ +__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" + +#define __IN(s,s1,i...) \ +__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \ +__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \ + + +#define RETURN_TYPE unsigned char +__IN(b,"") +#undef RETURN_TYPE +#define RETURN_TYPE unsigned short +__IN(w,"") +#undef RETURN_TYPE +#define RETURN_TYPE unsigned int +__IN(l,"") +#undef RETURN_TYPE + + + +__OUT(b,"b",char) +__OUT(w,"w",short) + + + + + +#if defined(__i386__) + +#define rdtscll(val) \ + __asm__ __volatile__("rdtsc" : "=A" (val)) + +#elif defined(__x86_64__) + +#define rdtscll(val) do { \ + unsigned int a,d; \ + asm volatile("rdtsc" : "=a" (a), "=d" (d)); \ + (val) = ((unsigned long)a) | (((unsigned long)d)<<32); \ + } while(0) + +#endif + +#define do_div(n,base) ({ \ + unsigned long __upper, __low, __high, __mod, __base; \ + __base = (base); \ + asm("":"=a" (__low), "=d" (__high):"A" (n)); \ + __upper = __high; \ + if (__high) { \ + __upper = __high % (__base); \ + __high = __high / (__base); \ + } \ + asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (__base), "0" (__low), "1" (__upper)); \ + asm("":"=A" (n):"a" (__low),"d" (__high)); \ + __mod; \ + }) + + +/** + * This uses the Programmable Interval Timer that is standard on all + * PC-compatible systems to determine the time stamp counter frequency. + * + * This uses the speaker output (channel 2) of the PIT. This is better than + * using the timer interrupt output because we can read the value of the + * speaker with just one inb(), where we need three i/o operations for the + * interrupt channel. We count how many ticks the TSC does in 50 ms. + * + * Returns the detected time stamp counter frequency in KHz. + */ + + +static unsigned int +pit_calibrate_tsc(void) +{ + uint_t khz = 0; + ullong_t start, end; + // unsigned long flags; + unsigned long pit_tick_rate = 1193182UL; /* 1.193182 MHz */ + + // spin_lock_irqsave(&pit_lock, flags); + + outb((inb(0x61) & ~0x02) | 0x01, 0x61); + + outb(0xb0, 0x43); + outb((pit_tick_rate / (1000 / 50)) & 0xff, 0x42); + outb((pit_tick_rate / (1000 / 50)) >> 8, 0x42); + // start = get_cycles_sync(); + rdtscll(start); + while ((inb(0x61) & 0x20) == 0); + rdtscll(end); + // end = get_cycles_sync(); + + // spin_unlock_irqrestore(&pit_lock, flags); + + + // return (end - start) / 50; + khz = end - start; +; + + return khz / 50; +} + + + +/* END JRL */ + + + /* @@ -51,7 +186,8 @@ int g_Quantum = DEFAULT_MAX_TICKS; * Ticks per second. * FIXME: should set this to something more reasonable, like 100. */ -#define TICKS_PER_SEC 18 +#define HZ 100 +//#define TICKS_PER_SEC 18 /*#define DEBUG_TIMER */ #ifdef DEBUG_TIMER @@ -155,12 +291,16 @@ static void Calibrate_Delay(void) ; /* - * Execute the spin loop. + * Execute the spin loop.xs * The temporary interrupt handler will overwrite the * loop counter when the next tick occurs. */ + + Spin(INT_MAX); + + Disable_Interrupts(); /* @@ -179,6 +319,9 @@ void Init_Timer(void) { ushort_t foo = 1193182L / HZ; + cpu_khz_freq = pit_calibrate_tsc(); + PrintBoth("CPU KHZ=%lu\n", (ulong_t)cpu_khz_freq); + PrintBoth("Initializing timer and setting to %d Hz...\n",HZ); /* Calibrate for delay loop */ @@ -198,7 +341,7 @@ void Init_Timer(void) } -#define US_PER_TICK (TICKS_PER_SEC * 1000000) +#define US_PER_TICK (HZ * 1000000) /* * Spin for at least given number of microseconds.