Author: laurent Date: 2009-01-15 00:25:41 +0100 (Thu, 15 Jan 2009) New Revision: 407
Modified: openbios-devel/arch/ppc/qemu/methods.c Log: PowerPC: Fix milliseconds prom call
The current implementation of the milliseconds prom call on PowerPC is totally buggy: - The timer frequency returned by get_timer_freq() does not correspond to the timer which is read. - The dividend and the divisor of the division are swapped - If called very often, this function is not precise - Depending on the timer frequency and of the frequency of the calls, the variable overflow after a few dozen of seconds.
Please find in this patch a totally new implementation. This fixes the problem observed with the quik when a timeout is defined.
The timer frequency is defined using #define, I wonder if there is a better place to put it.
It reads both low and high part of the timer to make sure there is no overflow. It also removes the function that returns 0 on the first call as this is not needed according to IEEE 1275-1994. Finally it computes the real value of the timer each time, instead of adding a small value to a variable at each function calls, in order to get a correct precision if this method is call very often.
(Aurelien Jarno)
Modified: openbios-devel/arch/ppc/qemu/methods.c =================================================================== --- openbios-devel/arch/ppc/qemu/methods.c 2009-01-13 20:24:52 UTC (rev 406) +++ openbios-devel/arch/ppc/qemu/methods.c 2009-01-14 23:25:41 UTC (rev 407) @@ -122,19 +122,28 @@ }
/* ( -- ms ) */ +#define TIMER_FREQUENCY 16600000ULL + static void ciface_milliseconds( ulong args[], ulong ret[] ) { - extern unsigned long get_timer_freq(void); - static ulong mticks=0, usecs=0; - ulong t; + ulong tbu, tbl, temp; + ullong ticks, msecs;
- asm volatile("mftb %0" : "=r" (t) : ); - if( mticks ) - usecs += get_timer_freq() / 1000000 * ( t-mticks ); - mticks = t; + asm volatile( + "1:\n" + "mftbu %2\n" + "mftb %0\n" + "mftbu %1\n" + "cmpw %2,%1\n" + "bne 1b\n" + : "=r"(tbl), "=r"(tbu), "=r"(temp) + : + : "cc");
- PUSH( usecs/1000 ); + ticks = (((ullong)tbu) << 32) | (ullong)tbl; + msecs = (1000 * ticks) / TIMER_FREQUENCY; + PUSH( msecs ); }