cpu: Fix a livelock in the o3 cpu.

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.
This commit is contained in:
Ali Saidi 2013-02-15 17:40:07 -05:00
parent d4eca0591d
commit b84bd3028c
2 changed files with 22 additions and 1 deletions

View 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);

View 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",