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