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:
parent
e88cffb30a
commit
c4a8e5c36c
1 changed files with 22 additions and 4 deletions
|
@ -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()) {
|
||||
|
|
Loading…
Reference in a new issue