mirror of https://github.com/acidanthera/audk.git
PcAtChipsetPkg AcpiTimerLib: Get more accurate TSC Frequency
Minimize the code overhead between the two TSC reads by adding new internal API to calculate TSC Frequency instead of reusing MicroSecondDelay (). Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Liming Gao <liming.gao@intel.com> Cc: Paul A Lohr <paul.a.lohr@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng <star.zeng@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
This commit is contained in:
parent
82df618711
commit
62b8b5be71
|
@ -1,7 +1,7 @@
|
||||||
/** @file
|
/** @file
|
||||||
ACPI Timer implements one instance of Timer Library.
|
ACPI Timer implements one instance of Timer Library.
|
||||||
|
|
||||||
Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
|
Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
|
||||||
This program and the accompanying materials
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
are licensed and made available under the terms and conditions of the BSD License
|
||||||
which accompanies this distribution. The full text of the license may be found at
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
|
@ -335,3 +335,57 @@ GetTimeInNanoSecond (
|
||||||
|
|
||||||
return NanoSeconds;
|
return NanoSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Calculate TSC frequency.
|
||||||
|
|
||||||
|
The TSC counting frequency is determined by comparing how far it counts
|
||||||
|
during a 100us period as determined by the ACPI timer. The ACPI timer is
|
||||||
|
used because it counts at a known frequency.
|
||||||
|
The TSC is sampled, followed by waiting for ACPI_TIMER_FREQUENCY / 10000
|
||||||
|
clocks of the ACPI timer, or 100us. The TSC is then sampled again. The
|
||||||
|
difference multiplied by 10000 is the TSC frequency. There will be a small
|
||||||
|
error because of the overhead of reading the ACPI timer. An attempt is
|
||||||
|
made to determine and compensate for this error.
|
||||||
|
|
||||||
|
@return The number of TSC counts per second.
|
||||||
|
|
||||||
|
**/
|
||||||
|
UINT64
|
||||||
|
InternalCalculateTscFrequency (
|
||||||
|
VOID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UINT64 StartTSC;
|
||||||
|
UINT64 EndTSC;
|
||||||
|
UINT16 TimerAddr;
|
||||||
|
UINT32 Ticks;
|
||||||
|
UINT64 TscFrequency;
|
||||||
|
BOOLEAN InterruptState;
|
||||||
|
|
||||||
|
InterruptState = SaveAndDisableInterrupts ();
|
||||||
|
|
||||||
|
TimerAddr = InternalAcpiGetAcpiTimerIoPort ();
|
||||||
|
Ticks = IoRead32 (TimerAddr) + (ACPI_TIMER_FREQUENCY / 10000); // Set Ticks to 100us in the future
|
||||||
|
|
||||||
|
StartTSC = AsmReadTsc (); // Get base value for the TSC
|
||||||
|
//
|
||||||
|
// Wait until the ACPI timer has counted 100us.
|
||||||
|
// Timer wrap-arounds are handled correctly by this function.
|
||||||
|
// When the current ACPI timer value is greater than 'Ticks', the while loop will exit.
|
||||||
|
//
|
||||||
|
while (((Ticks - IoRead32 (TimerAddr)) & BIT23) == 0) {
|
||||||
|
CpuPause();
|
||||||
|
}
|
||||||
|
EndTSC = AsmReadTsc (); // TSC value 100us later
|
||||||
|
|
||||||
|
TscFrequency = MultU64x32 (
|
||||||
|
(EndTSC - StartTSC), // Number of TSC counts in 100us
|
||||||
|
10000 // Number of 100us in a second
|
||||||
|
);
|
||||||
|
|
||||||
|
SetInterruptState (InterruptState);
|
||||||
|
|
||||||
|
return TscFrequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/** @file
|
/** @file
|
||||||
ACPI Timer implements one instance of Timer Library.
|
ACPI Timer implements one instance of Timer Library.
|
||||||
|
|
||||||
Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
|
Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
|
||||||
This program and the accompanying materials
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
are licensed and made available under the terms and conditions of the BSD License
|
||||||
which accompanies this distribution. The full text of the license may be found at
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
|
@ -16,6 +16,26 @@
|
||||||
#include <Library/TimerLib.h>
|
#include <Library/TimerLib.h>
|
||||||
#include <Library/BaseLib.h>
|
#include <Library/BaseLib.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
Calculate TSC frequency.
|
||||||
|
|
||||||
|
The TSC counting frequency is determined by comparing how far it counts
|
||||||
|
during a 100us period as determined by the ACPI timer. The ACPI timer is
|
||||||
|
used because it counts at a known frequency.
|
||||||
|
The TSC is sampled, followed by waiting for ACPI_TIMER_FREQUENCY / 10000
|
||||||
|
clocks of the ACPI timer, or 100us. The TSC is then sampled again. The
|
||||||
|
difference multiplied by 10000 is the TSC frequency. There will be a small
|
||||||
|
error because of the overhead of reading the ACPI timer. An attempt is
|
||||||
|
made to determine and compensate for this error.
|
||||||
|
|
||||||
|
@return The number of TSC counts per second.
|
||||||
|
|
||||||
|
**/
|
||||||
|
UINT64
|
||||||
|
InternalCalculateTscFrequency (
|
||||||
|
VOID
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Internal function to retrieves the 64-bit frequency in Hz.
|
Internal function to retrieves the 64-bit frequency in Hz.
|
||||||
|
|
||||||
|
@ -29,14 +49,5 @@ InternalGetPerformanceCounterFrequency (
|
||||||
VOID
|
VOID
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
BOOLEAN InterruptState;
|
return InternalCalculateTscFrequency ();
|
||||||
UINT64 Count;
|
|
||||||
UINT64 Frequency;
|
|
||||||
|
|
||||||
InterruptState = SaveAndDisableInterrupts ();
|
|
||||||
Count = GetPerformanceCounter ();
|
|
||||||
MicroSecondDelay (100);
|
|
||||||
Frequency = MultU64x32 (GetPerformanceCounter () - Count, 10000);
|
|
||||||
SetInterruptState (InterruptState);
|
|
||||||
return Frequency;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/** @file
|
/** @file
|
||||||
ACPI Timer implements one instance of Timer Library.
|
ACPI Timer implements one instance of Timer Library.
|
||||||
|
|
||||||
Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
|
Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
|
||||||
This program and the accompanying materials
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
are licensed and made available under the terms and conditions of the BSD License
|
||||||
which accompanies this distribution. The full text of the license may be found at
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
|
@ -16,6 +16,26 @@
|
||||||
#include <Library/TimerLib.h>
|
#include <Library/TimerLib.h>
|
||||||
#include <Library/BaseLib.h>
|
#include <Library/BaseLib.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
Calculate TSC frequency.
|
||||||
|
|
||||||
|
The TSC counting frequency is determined by comparing how far it counts
|
||||||
|
during a 100us period as determined by the ACPI timer. The ACPI timer is
|
||||||
|
used because it counts at a known frequency.
|
||||||
|
The TSC is sampled, followed by waiting for ACPI_TIMER_FREQUENCY / 10000
|
||||||
|
clocks of the ACPI timer, or 100us. The TSC is then sampled again. The
|
||||||
|
difference multiplied by 10000 is the TSC frequency. There will be a small
|
||||||
|
error because of the overhead of reading the ACPI timer. An attempt is
|
||||||
|
made to determine and compensate for this error.
|
||||||
|
|
||||||
|
@return The number of TSC counts per second.
|
||||||
|
|
||||||
|
**/
|
||||||
|
UINT64
|
||||||
|
InternalCalculateTscFrequency (
|
||||||
|
VOID
|
||||||
|
);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Cached performance counter frequency
|
// Cached performance counter frequency
|
||||||
//
|
//
|
||||||
|
@ -34,15 +54,8 @@ InternalGetPerformanceCounterFrequency (
|
||||||
VOID
|
VOID
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
BOOLEAN InterruptState;
|
|
||||||
UINT64 Count;
|
|
||||||
|
|
||||||
if (mPerformanceCounterFrequency == 0) {
|
if (mPerformanceCounterFrequency == 0) {
|
||||||
InterruptState = SaveAndDisableInterrupts ();
|
mPerformanceCounterFrequency = InternalCalculateTscFrequency ();
|
||||||
Count = GetPerformanceCounter ();
|
|
||||||
MicroSecondDelay (100);
|
|
||||||
mPerformanceCounterFrequency = MultU64x32 (GetPerformanceCounter () - Count, 10000);
|
|
||||||
SetInterruptState (InterruptState);
|
|
||||||
}
|
}
|
||||||
return mPerformanceCounterFrequency;
|
return mPerformanceCounterFrequency;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue