From ac5c5785b1d0bf6ffbe2e803d7118f3b5a793986 Mon Sep 17 00:00:00 2001
From: Laszlo Ersek <lersek@redhat.com>
Date: Thu, 5 Feb 2015 17:53:53 +0100
Subject: ArmPkg: TimerDxe: smack down spurious timer interrupt (RHELSA hack)

Message-id: <1423155233-22668-2-git-send-email-lersek@redhat.com>
Patchwork-id: 63732
O-Subject:  [RHELSA AAVMF PATCH 1/1] ArmPkg: TimerDxe: smack down spurious timer
	interrupt (RHELSA hack)
Bugzilla: 1188054
Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
Acked-by: wei@redhat.com
Acked-by: Andrew Jones <drjones@redhat.com>

When an aarch64 KVM guest is rebooted with the UEFI shell command "reset
-c", the instance of AAVMF that runs after the reboot hangs in the timer
driver. We tracked this issue unto a virtual timer interrupt that remains
stuck / asserted across the reboot for some reason, and is delivered to
the handler function in TimerDxe *before* TimerDxe is done setting up data
for the handler and unmasks the interrupt. This happens to cause an
infinite loop in the handler.

The above situation should never emerge (an interrupt, stuck or not,
should never be delivered while it is masked). This could be a KVM bug --
which we track with clone bug 1189429 and reported privately to ARM &
Linaro people --, but until the root cause gets sorted out, we need to
move forward with AAVMF. Attempts to clear interrupt lines up-front have
borne no fruit. Hence we enable the handler to cope with a spurious
interrupt.

Downstream only. Should be reverted when 1189429 is fixed.

Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 ArmPkg/Drivers/TimerDxe/TimerDxe.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/ArmPkg/Drivers/TimerDxe/TimerDxe.c b/ArmPkg/Drivers/TimerDxe/TimerDxe.c
index 1169d42..6a8c312 100644
--- a/ArmPkg/Drivers/TimerDxe/TimerDxe.c
+++ b/ArmPkg/Drivers/TimerDxe/TimerDxe.c
@@ -313,6 +313,12 @@ TimerInterruptHandler (
     // Signal end of interrupt early to help avoid losing subsequent ticks from long duration handlers
     gInterrupt->EndOfInterrupt (gInterrupt, Source);
 
+    if (mTimerPeriod == 0) {
+      DEBUG ((EFI_D_WARN, "%a: hack: this should never happen; dodged spurious"
+        " interrupt 0x%Lx\n", __FUNCTION__, (UINT64)Source));
+      goto Done;
+    }
+
     if (mTimerNotifyFunction) {
       mTimerNotifyFunction (mTimerPeriod * mElapsedPeriod);
     }
@@ -340,6 +346,7 @@ TimerInterruptHandler (
     ArmGenericTimerEnableTimer ();
   }
 
+Done:
   // Enable timer interrupts
   gInterrupt->EnableInterruptSource (gInterrupt, Source);
 
-- 
1.8.3.1