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/systime…
==============================================================================
--- 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?…
==============================================================================
--- 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);