arm: Handle functional TLB walks properly

The table walker code currently accounts for two types of walks,
Atomic and Timing, and treats them differently. Atomic walks keep a
single instance of WalkerState around for all walks to use in
currState. Timing mode keeps a queue of in-flight WalkerStates and
maintains currState as NULL between walks.

If a functional walk is done during Timing mode, it is treated as an
atomic walk and either creates a persistent WalkerState if in between
Timing walks, or stomps an existing currState for an in-progress
Timing walk.

This patch distinguishes functional walks as being able to exist at
any time and sets up a temporary WalkerState for its exclusive use and
then cleans up when finished, leaving any in progress Atomic or Timing
walks undisturbed.
This commit is contained in:
Geoffrey Blake 2014-03-07 15:56:23 -05:00
parent e88cffb30a
commit c4a8e5c36c

View file

@ -160,13 +160,22 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint16_t _asid,
bool secure, TLB::ArmTranslationType tranType)
{
assert(!(_functional && _timing));
WalkerState *savedCurrState = NULL;
if (!currState) {
if (!currState && !_functional) {
// For atomic mode, a new WalkerState instance should be only created
// once per TLB. For timing mode, a new instance is generated for every
// TLB miss.
DPRINTF(TLBVerbose, "creating new instance of WalkerState\n");
currState = new WalkerState();
currState->tableWalker = this;
} else if (_functional) {
// If we are mixing functional mode with timing (or even
// atomic), we need to to be careful and clean up after
// ourselves to not risk getting into an inconsistent state.
DPRINTF(TLBVerbose, "creating functional instance of WalkerState\n");
savedCurrState = currState;
currState = new WalkerState();
currState->tableWalker = this;
} else if (_timing) {
@ -264,12 +273,21 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint16_t _asid,
}
if (!currState->timing) {
Fault fault = NoFault;
if (currState->aarch64)
return processWalkAArch64();
fault = processWalkAArch64();
else if (long_desc_format)
return processWalkLPAE();
fault = processWalkLPAE();
else
return processWalk();
fault = processWalk();
// If this was a functional non-timing access restore state to
// how we found it.
if (currState->functional) {
delete currState;
currState = savedCurrState;
}
return fault;
}
if (pending || pendingQueue.size()) {