summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cpu/o3/commit.hh6
-rw-r--r--src/cpu/o3/commit_impl.hh17
2 files changed, 22 insertions, 1 deletions
diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh
index c76d6c1d0..62aa274c2 100644
--- a/src/cpu/o3/commit.hh
+++ b/src/cpu/o3/commit.hh
@@ -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);
diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh
index ea709e92c..6ac946ac1 100644
--- a/src/cpu/o3/commit_impl.hh
+++ b/src/cpu/o3/commit_impl.hh
@@ -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",