+\r
+/**\r
+ Calculate TSC frequency.\r
+\r
+ The TSC counting frequency is determined by comparing how far it counts\r
+ during a 100us period as determined by the ACPI timer. The ACPI timer is\r
+ used because it counts at a known frequency.\r
+ The TSC is sampled, followed by waiting for ACPI_TIMER_FREQUENCY / 10000\r
+ clocks of the ACPI timer, or 100us. The TSC is then sampled again. The\r
+ difference multiplied by 10000 is the TSC frequency. There will be a small\r
+ error because of the overhead of reading the ACPI timer. An attempt is\r
+ made to determine and compensate for this error.\r
+\r
+ @return The number of TSC counts per second.\r
+\r
+**/\r
+UINT64\r
+InternalCalculateTscFrequency (\r
+ VOID\r
+ )\r
+{\r
+ UINT64 StartTSC;\r
+ UINT64 EndTSC;\r
+ UINT16 TimerAddr;\r
+ UINT32 Ticks;\r
+ UINT64 TscFrequency;\r
+ BOOLEAN InterruptState;\r
+\r
+ InterruptState = SaveAndDisableInterrupts ();\r
+\r
+ TimerAddr = InternalAcpiGetAcpiTimerIoPort ();\r
+ Ticks = IoRead32 (TimerAddr) + (ACPI_TIMER_FREQUENCY / 10000); // Set Ticks to 100us in the future\r
+\r
+ StartTSC = AsmReadTsc (); // Get base value for the TSC\r
+ //\r
+ // Wait until the ACPI timer has counted 100us.\r
+ // Timer wrap-arounds are handled correctly by this function.\r
+ // When the current ACPI timer value is greater than 'Ticks', the while loop will exit.\r
+ //\r
+ while (((Ticks - IoRead32 (TimerAddr)) & BIT23) == 0) {\r
+ CpuPause();\r
+ }\r
+ EndTSC = AsmReadTsc (); // TSC value 100us later\r
+\r
+ TscFrequency = MultU64x32 (\r
+ (EndTSC - StartTSC), // Number of TSC counts in 100us\r
+ 10000 // Number of 100us in a second\r
+ );\r
+\r
+ SetInterruptState (InterruptState);\r
+\r
+ return TscFrequency;\r
+}\r
+\r