Author: fireball Date: Sat Oct 10 20:22:56 2009 New Revision: 43364
URL: http://svn.reactos.org/svn/reactos?rev=43364&view=rev Log: [ntoskrnl] - Reimplement HalpCalibrateStallExecution which was removed in r24964. Real Windows uses a different algorithm, however existing one seems to work acceptably. This patch is critical for devices support on real hardware. The only downside is that uniata initialization takes a substantial amount of time now, this is going to be investigated. Patch by Daniel Zimmermann. See issue #4600 for more details.
Modified: trunk/reactos/hal/halx86/generic/halinit.c trunk/reactos/hal/halx86/generic/systimer.S trunk/reactos/hal/halx86/generic/timer.c trunk/reactos/hal/halx86/include/halp.h
Modified: trunk/reactos/hal/halx86/generic/halinit.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/generic/halinit.... ============================================================================== --- trunk/reactos/hal/halx86/generic/halinit.c [iso-8859-1] (original) +++ trunk/reactos/hal/halx86/generic/halinit.c [iso-8859-1] Sat Oct 10 20:22:56 2009 @@ -101,7 +101,7 @@ HalpInitializeClock();
/* Setup busy waiting */ - //HalpCalibrateStallExecution(); + HalpCalibrateStallExecution();
/* Fill out the dispatch tables */ HalQuerySystemInformation = HaliQuerySystemInformation;
Modified: trunk/reactos/hal/halx86/generic/systimer.S URL: http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/generic/systimer... ============================================================================== --- trunk/reactos/hal/halx86/generic/systimer.S [iso-8859-1] (original) +++ trunk/reactos/hal/halx86/generic/systimer.S [iso-8859-1] Sat Oct 10 20:22:56 2009 @@ -54,6 +54,34 @@ ret 4 .endfunc
+ +.globl _HalpQuery8254Counter@0 +.func HalpQuery8254Counter@0 +_HalpQuery8254Counter@0: + + /* Save EFLAGS and disable interrupts */ + pushfd + cli + + /* Set timer data */ + mov al, 0 + out 0x43, al + jmp $+2 + + /* Read current timer */ + in al, 0x40 + jmp $+2 + movzx ecx, al + in al, 0x40 + mov ch, al + + /* Return it and restore interrupt state */ + mov eax, ecx + popfd + ret +.endfunc + + .global _KeQueryPerformanceCounter@4 .func KeQueryPerformanceCounter@4 _KeQueryPerformanceCounter@4:
Modified: trunk/reactos/hal/halx86/generic/timer.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/generic/timer.c?... ============================================================================== --- trunk/reactos/hal/halx86/generic/timer.c [iso-8859-1] (original) +++ trunk/reactos/hal/halx86/generic/timer.c [iso-8859-1] Sat Oct 10 20:22:56 2009 @@ -13,6 +13,11 @@ #include <debug.h>
/* GLOBALS *******************************************************************/ + +/* time to wait */ +#define MICROSECOND_TO_WAIT 1000 +/* the tick count for 1 ms is 1193.182 (1193182 Hz) round it up */ +#define TICKCOUNT_TO_WAIT 1194
BOOLEAN HalpClockSetMSRate; ULONG HalpCurrentTimeIncrement; @@ -130,4 +135,161 @@ return HalpRolloverTable[Increment - 1].HighPart; }
+ULONG +WaitFor8254Wraparound(VOID) +{ + ULONG StartTicks; + ULONG PrevTicks; + LONG Delta; + + StartTicks = HalpQuery8254Counter(); + + do + { + PrevTicks = StartTicks; + StartTicks = HalpQuery8254Counter(); + Delta = StartTicks - PrevTicks; + + /* + * This limit for delta seems arbitrary, but it isn't, it's + * slightly above the level of error a buggy Mercury/Neptune + * chipset timer can cause. + */ + + } + while (Delta < 300); + + return StartTicks; +} + +VOID +NTAPI +HalpCalibrateStallExecution(VOID) +{ + ULONG CalibrationBit; + ULONG EndTicks; + ULONG StartTicks; + ULONG OverheadTicks; + PKIPCR Pcr; + + Pcr = (PKIPCR)KeGetPcr(); + + /* Measure the delay for the minimum call overhead in ticks */ + Pcr->StallScaleFactor = 1; + StartTicks = WaitFor8254Wraparound(); + KeStallExecutionProcessor(1); + EndTicks = HalpQuery8254Counter(); + OverheadTicks = (StartTicks - EndTicks); + + do + { + /* Increase the StallScaleFactor */ + Pcr->StallScaleFactor = Pcr->StallScaleFactor * 2; + + if (Pcr->StallScaleFactor == 0) + { + /* Nothing found */ + break; + } + + /* Get the start ticks */ + StartTicks = WaitFor8254Wraparound(); + + /* Wait for a defined time */ + KeStallExecutionProcessor(MICROSECOND_TO_WAIT); + + /* Get the end ticks */ + EndTicks = HalpQuery8254Counter(); + + DPRINT("Pcr->StallScaleFactor: %d\n", Pcr->StallScaleFactor); + DPRINT("Time1 : StartTicks %i - EndTicks %i = %i\n", + StartTicks, EndTicks, StartTicks - EndTicks); + } while ((StartTicks - EndTicks) <= (TICKCOUNT_TO_WAIT + OverheadTicks)); + + /* A StallScaleFactor lesser than INITIAL_STALL_COUNT makes no sense */ + if (Pcr->StallScaleFactor >= (INITIAL_STALL_COUNT * 2)) + { + /* Adjust the StallScaleFactor */ + Pcr->StallScaleFactor = Pcr->StallScaleFactor / 2; + + /* Setup the CalibrationBit */ + CalibrationBit = Pcr->StallScaleFactor; + + for (;;) + { + /* Lower the CalibrationBit */ + CalibrationBit = CalibrationBit / 2; + if (CalibrationBit == 0) + { + break; + } + + /* Add the CalibrationBit */ + Pcr->StallScaleFactor = Pcr->StallScaleFactor + CalibrationBit; + + /* Get the start ticks */ + StartTicks = WaitFor8254Wraparound(); + + /* Wait for a defined time */ + KeStallExecutionProcessor(MICROSECOND_TO_WAIT); + + /* Get the end ticks */ + EndTicks = HalpQuery8254Counter(); + + DPRINT("Pcr->StallScaleFactor: %d\n", Pcr->StallScaleFactor); + DPRINT("Time2 : StartTicks %i - EndTicks %i = %i\n", + StartTicks, EndTicks, StartTicks - EndTicks); + + if ((StartTicks-EndTicks) > (TICKCOUNT_TO_WAIT+OverheadTicks)) + { + /* Too big so subtract the CalibrationBit */ + Pcr->StallScaleFactor = Pcr->StallScaleFactor - CalibrationBit; + } + } + DPRINT("New StallScaleFactor: %d\n", Pcr->StallScaleFactor); + } + else + { + /* Set StallScaleFactor to the default */ + Pcr->StallScaleFactor = INITIAL_STALL_COUNT; + } + +#if 0 + /* For debugging */ + ULONG i; + + DPRINT1("About to start delay loop test\n"); + DPRINT1("Waiting for a minute..."); + for (i = 0; i < (60*1000*20); i++) + { + KeStallExecutionProcessor(50); + } + DPRINT1("finished\n"); + + + DPRINT1("About to start delay loop test\n"); + DPRINT1("Waiting for a minute..."); + for (i = 0; i < (60*1000); i++) + { + KeStallExecutionProcessor(1000); + } + DPRINT1("finished\n"); + + + DPRINT1("About to start delay loop test\n"); + DPRINT1("Waiting for a minute..."); + for (i = 0; i < (60*1000*1000); i++) + { + KeStallExecutionProcessor(1); + } + DPRINT1("finished\n"); + + DPRINT1("About to start delay loop test\n"); + DPRINT1("Waiting for a minute..."); + KeStallExecutionProcessor(60*1000000); + DPRINT1("finished\n"); +#endif +} + + /* EOF */
Modified: trunk/reactos/hal/halx86/include/halp.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/include/halp.h?r... ============================================================================== --- trunk/reactos/hal/halx86/include/halp.h [iso-8859-1] (original) +++ trunk/reactos/hal/halx86/include/halp.h [iso-8859-1] Sat Oct 10 20:22:56 2009 @@ -40,6 +40,16 @@
/* udelay.c */ VOID NTAPI HalpInitializeClock(VOID); + +VOID +NTAPI +HalpCalibrateStallExecution(VOID); + +ULONG +NTAPI +HalpQuery8254Counter( + VOID +);
/* pci.c */ VOID HalpInitPciBus (VOID);