dev-arm: Make generic timer work with level-sensitive support
authorHsuan Hsu <hsuan.hsu@mediatek.com>
Wed, 27 May 2020 07:41:39 +0000 (15:41 +0800)
committerHsuan Hsu <kugwa2000@gmail.com>
Fri, 10 Jul 2020 18:03:15 +0000 (18:03 +0000)
Support for level-sensitive PPIs and SPIs has been added to GICv2 now.
It is therefore the timer's responsibility to notify GICv2 to clear its
interrupt pending state. Without doing this, the guest will get stuck
in just a single round of the interrupt handler because GICv2 does not
clear the pending state, and eventually make the guest treat this
interrupt as problematic and then just disable it.

JIRA: https://gem5.atlassian.net/browse/GEM5-663

Change-Id: Ia8fd96bf00b28e91aa440274e6f8bb000446fbe3
Signed-off-by: Hsuan Hsu <hsuan.hsu@mediatek.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/30916
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
src/dev/arm/generic_timer.cc

index 1b7572838e5b1f4d8d4cec3dac88f6c45c300d76..42b03adfae6aca8d8b033a230bab0012ad8e3bd4 100644 (file)
@@ -281,7 +281,11 @@ ArchTimer::updateCounter()
     if (value() >= _counterLimit) {
         counterLimitReached();
     } else {
-        _control.istatus = 0;
+        if (_control.istatus) {
+            DPRINTF(Timer, "Clearing interrupt\n");
+            _interrupt->clear();
+            _control.istatus = 0;
+        }
         if (scheduleEvents()) {
             _parent.schedule(_counterLimitReachedEvent,
                              whenValue(_counterLimit));
@@ -313,8 +317,13 @@ ArchTimer::setControl(uint32_t val)
     if (!old_ctl.enable && new_ctl.enable)
         updateCounter();
     // Timer disabled
-    else if (old_ctl.enable && !new_ctl.enable)
-        _control.istatus = 0;
+    else if (old_ctl.enable && !new_ctl.enable) {
+        if (_control.istatus) {
+            DPRINTF(Timer, "Clearing interrupt\n");
+            _interrupt->clear();
+            _control.istatus = 0;
+        }
+    }
 }
 
 void