ArmPkg: Fix timer wrap-around

The timer counter register can wrap around and when this happens,
we'll get misbehavior for any MicroSecondDelay() calls. This adds
handling for that.

Signed-off-by: Carsten Haitzler <carsten.haitzler@foss.arm.com>
This commit is contained in:
Carsten Haitzler 2024-05-17 11:49:22 +01:00 committed by mergify[bot]
parent 4ef87f455b
commit af15e4535d
1 changed files with 10 additions and 4 deletions

View File

@ -62,6 +62,8 @@ MicroSecondDelay (
{
UINT64 TimerTicks64;
UINT64 SystemCounterVal;
UINT64 PreviousSystemCounterVal;
UINT64 DeltaCounterVal;
// Calculate counter ticks that represent requested delay:
// = MicroSeconds x TICKS_PER_MICRO_SEC
@ -75,13 +77,17 @@ MicroSecondDelay (
);
// Read System Counter value
SystemCounterVal = ArmGenericTimerGetSystemCount ();
TimerTicks64 += SystemCounterVal;
PreviousSystemCounterVal = ArmGenericTimerGetSystemCount ();
// Wait until delay count expires.
while (SystemCounterVal < TimerTicks64) {
while (TimerTicks64 > 0) {
SystemCounterVal = ArmGenericTimerGetSystemCount ();
// Get how much we advanced this tick. Wrap around still has delta correct
DeltaCounterVal = (SystemCounterVal - PreviousSystemCounterVal)
& (MAX_UINT64 >> 8); // Account for a lesser (minimum) size
// Never wrap back around below zero by choosing the min and thus stop at 0
TimerTicks64 -= MIN (TimerTicks64, DeltaCounterVal);
PreviousSystemCounterVal = SystemCounterVal;
}
return MicroSeconds;