ArmPkg/TimerDxe: Fixed real time period

Prior to this change, the TimerPeriod was re-initialize at the
end of the interrupt handling with the value of the period.
It means the real timer period was: Timer Interrupt Processing
time + Timer Period

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Olivier Martin <olivier.martin@arm.com>



git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15923 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Olivier Martin 2014-08-27 10:13:36 +00:00 committed by oliviermartin
parent 09c1b24c2f
commit c6c4df80de
1 changed files with 50 additions and 8 deletions

View File

@ -35,6 +35,10 @@ EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
// The current period of the timer interrupt // The current period of the timer interrupt
UINT64 mTimerPeriod = 0; UINT64 mTimerPeriod = 0;
// The latest Timer Tick calculated for mTimerPeriod
UINT64 mTimerTicks = 0;
// Number of elapsed period since the last Timer interrupt
UINT64 mElapsedPeriod = 1;
// Cached copy of the Hardware Interrupt protocol instance // Cached copy of the Hardware Interrupt protocol instance
EFI_HARDWARE_INTERRUPT_PROTOCOL *gInterrupt = NULL; EFI_HARDWARE_INTERRUPT_PROTOCOL *gInterrupt = NULL;
@ -135,26 +139,44 @@ TimerDriverSetTimerPeriod (
IN UINT64 TimerPeriod IN UINT64 TimerPeriod
) )
{ {
UINT64 CounterValue;
UINT64 TimerTicks; UINT64 TimerTicks;
EFI_TPL OriginalTPL;
// Always disable the timer // Always disable the timer
ArmArchTimerDisableTimer (); ArmArchTimerDisableTimer ();
if (TimerPeriod != 0) { if (TimerPeriod != 0) {
// TimerTicks = TimerPeriod in 1ms unit x Frequency.10^-3 // mTimerTicks = TimerPeriod in 1ms unit x Frequency.10^-3
// = TimerPeriod.10^-4 x Frequency.10^-3 // = TimerPeriod.10^-4 x Frequency.10^-3
// = (TimerPeriod x Frequency) x 10^-7 // = (TimerPeriod x Frequency) x 10^-7
TimerTicks = MultU64x32 (TimerPeriod, FixedPcdGet32 (PcdArmArchTimerFreqInHz)); TimerTicks = MultU64x32 (TimerPeriod, FixedPcdGet32 (PcdArmArchTimerFreqInHz));
TimerTicks = DivU64x32 (TimerTicks, 10000000U); TimerTicks = DivU64x32 (TimerTicks, 10000000U);
ArmArchTimerSetTimerVal ((UINTN)TimerTicks); // Raise TPL to update the mTimerTicks and mTimerPeriod to ensure these values
// are coherent in the interrupt handler
OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
mTimerTicks = TimerTicks;
mTimerPeriod = TimerPeriod;
mElapsedPeriod = 1;
gBS->RestoreTPL (OriginalTPL);
// Get value of the current physical timer
CounterValue = ArmReadCntPct ();
// Set the interrupt in Current Time + mTimerTick
ArmWriteCntpCval (CounterValue + mTimerTicks);
// Enable the timer // Enable the timer
ArmArchTimerEnableTimer (); ArmArchTimerEnableTimer ();
} else {
// Save the new timer period
mTimerPeriod = TimerPeriod;
// Reset the elapsed period
mElapsedPeriod = 1;
} }
// Save the new timer period
mTimerPeriod = TimerPeriod;
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@ -274,6 +296,8 @@ TimerInterruptHandler (
) )
{ {
EFI_TPL OriginalTPL; EFI_TPL OriginalTPL;
UINT64 CurrentValue;
UINT64 CompareValue;
// //
// DXE core uses this callback for the EFI timer tick. The DXE core uses locks // DXE core uses this callback for the EFI timer tick. The DXE core uses locks
@ -289,11 +313,29 @@ TimerInterruptHandler (
gInterrupt->EndOfInterrupt (gInterrupt, Source); gInterrupt->EndOfInterrupt (gInterrupt, Source);
if (mTimerNotifyFunction) { if (mTimerNotifyFunction) {
mTimerNotifyFunction (mTimerPeriod); mTimerNotifyFunction (mTimerPeriod * mElapsedPeriod);
} }
//
// Reload the Timer // Reload the Timer
TimerDriverSetTimerPeriod (&gTimer, mTimerPeriod); //
// Get current counter value
CurrentValue = ArmReadCntPct ();
// Get the counter value to compare with
CompareValue = ArmReadCntpCval ();
// This loop is needed in case we missed interrupts (eg: case when the interrupt handling
// has taken longer than mTickPeriod).
// Note: Physical Counter is counting up
mElapsedPeriod = 0;
do {
CompareValue += mTimerTicks;
mElapsedPeriod++;
} while (CompareValue < CurrentValue);
// Set next compare value
ArmWriteCntpCval (CompareValue);
} }
// Enable timer interrupts // Enable timer interrupts