dev-arm: Fix GICv3 ITS cmdq wrapping
authorGiacomo Travaglini <giacomo.travaglini@arm.com>
Tue, 20 Aug 2019 19:47:55 +0000 (20:47 +0100)
committerGiacomo Travaglini <giacomo.travaglini@arm.com>
Mon, 9 Sep 2019 08:48:30 +0000 (08:48 +0000)
Change-Id: I979e8d1378d5b5d2647158798479cf4238f2c349
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/20633
Tested-by: kokoro <noreply+kokoro@google.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>

src/dev/arm/gic_v3_its.cc
src/dev/arm/gic_v3_its.hh

index ca363f409b90895a9b3430a287a9d8fc1dd83947..ab0d8c2d0fa1caeadd6455482733687c3a6e3cc5 100644 (file)
@@ -1065,19 +1065,30 @@ Gicv3Its::incrementReadPointer()
     gitsCreadr.offset = gitsCreadr.offset + 1;
 
     // Check for wrapping
-    auto queue_end = (4096 * (gitsCbaser.size + 1));
-
-    if (gitsCreadr.offset == queue_end) {
+    if (gitsCreadr.offset == maxCommands()) {
         gitsCreadr.offset = 0;
     }
 }
 
+uint64_t
+Gicv3Its::maxCommands() const
+{
+    return (4096 * (gitsCbaser.size + 1)) / sizeof(ItsCommand::CommandEntry);
+}
+
 void
 Gicv3Its::checkCommandQueue()
 {
     if (!gitsControl.enabled || !gitsCbaser.valid)
         return;
 
+    // If GITS_CWRITER gets set by sw to a value bigger than the
+    // allowed one, the command queue should stop processing commands
+    // until the register gets reset to an allowed one
+    if (gitsCwriter.offset >= maxCommands()) {
+        return;
+    }
+
     if (gitsCwriter.offset != gitsCreadr.offset) {
         // writer and reader pointing to different command
         // entries: queue not empty.
index b9c1d8582630f0b7a667961ef221a2e866a9dae3..d11d7c0d7fa4e0816fbb6222ead0f44405c10a2c 100644 (file)
@@ -257,6 +257,7 @@ class Gicv3Its : public BasicPioDevice
     bool lpiOutOfRange(uint32_t intid) const;
 
   private: // Command
+    uint64_t maxCommands() const;
     void checkCommandQueue();
     void incrementReadPointer();