cpu: Fix a livelock in the o3 cpu.
authorAli Saidi <Ali.Saidi@ARM.com>
Fri, 15 Feb 2013 22:40:07 +0000 (17:40 -0500)
committerAli Saidi <Ali.Saidi@ARM.com>
Fri, 15 Feb 2013 22:40:07 +0000 (17:40 -0500)
Check if an instruction just enabled interrupts and we've previously had an
interrupt pending that was not handled because interrupts were subsequently
disabled before the pipeline reached a place to handle the interrupt. In that
case squash now to make sure the interrupt is handled.

src/cpu/o3/commit.hh
src/cpu/o3/commit_impl.hh

index c76d6c1d0394adb5be327a1fc990ff0e0e038339..62aa274c2c0f493bdf190620703c1f83b729df9d 100644 (file)
@@ -479,6 +479,12 @@ class DefaultCommit
     /** True if last committed microop can be followed by an interrupt */
     bool canHandleInterrupts;
 
+    /** Have we had an interrupt pending and then seen it de-asserted because
+        of a masking change? In this case the variable is set and the next time
+        interrupts are enabled and pending the pipeline will squash to avoid
+        a possible livelock senario.  */
+    bool avoidQuiesceLiveLock;
+
     /** Updates commit stats based on this instruction. */
     void updateComInstStats(DynInstPtr &inst);
 
index ea709e92c1ab8ddd6bafe5bee22d67b872499f4b..6ac946ac18a9031641a529e0b8f050632462cd0c 100644 (file)
@@ -101,7 +101,8 @@ DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params)
       numThreads(params->numThreads),
       drainPending(false),
       trapLatency(params->trapLatency),
-      canHandleInterrupts(true)
+      canHandleInterrupts(true),
+      avoidQuiesceLiveLock(false)
 {
     _status = Active;
     _nextStatus = Inactive;
@@ -728,6 +729,7 @@ DefaultCommit<Impl>::handleInterrupt()
                 "it got handled. Restart fetching from the orig path.\n");
         toIEW->commitInfo[0].clearInterrupt = true;
         interrupt = NoFault;
+        avoidQuiesceLiveLock = true;
         return;
     }
 
@@ -759,6 +761,7 @@ DefaultCommit<Impl>::handleInterrupt()
         generateTrapEvent(0);
 
         interrupt = NoFault;
+        avoidQuiesceLiveLock = false;
     } else {
         DPRINTF(Commit, "Interrupt pending: instruction is %sin "
                 "flight, ROB is %sempty\n",
@@ -1058,6 +1061,18 @@ DefaultCommit<Impl>::commitInsts()
                             "PC skip function event, stopping commit\n");
                     break;
                 }
+
+                // Check if an instruction just enabled interrupts and we've
+                // previously had an interrupt pending that was not handled
+                // because interrupts were subsequently disabled before the
+                // pipeline reached a place to handle the interrupt. In that
+                // case squash now to make sure the interrupt is handled.
+                //
+                // If we don't do this, we might end up in a live lock situation
+                if (!interrupt  && avoidQuiesceLiveLock &&
+                   (!head_inst->isMicroop() || head_inst->isLastMicroop()) &&
+                   cpu->checkInterrupts(cpu->tcBase(0)))
+                    squashAfter(tid, head_inst);
             } else {
                 DPRINTF(Commit, "Unable to commit head instruction PC:%s "
                         "[tid:%i] [sn:%i].\n",