summaryrefslogtreecommitdiff
path: root/src/arch/arm/table_walker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/arm/table_walker.cc')
-rw-r--r--src/arch/arm/table_walker.cc33
1 files changed, 24 insertions, 9 deletions
diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc
index 44f12833b..9755299ff 100644
--- a/src/arch/arm/table_walker.cc
+++ b/src/arch/arm/table_walker.cc
@@ -186,8 +186,15 @@ TableWalker::processWalkWrapper()
assert(pendingQueue.size());
currState = pendingQueue.front();
-
- if (!currState->transState->squashed()) {
+ // Check if a previous walk filled this request already
+ TlbEntry* te = tlb->lookup(currState->vaddr, currState->contextId, true);
+
+ // Check if we still need to have a walk for this request. If the requesting
+ // instruction has been squashed, or a previous walk has filled the TLB with
+ // a match, we just want to get rid of the walk. The latter could happen
+ // when there are multiple outstanding misses to a single page and a
+ // previous request has been successfully translated.
+ if (!currState->transState->squashed() && !te) {
// We've got a valid request, lets process it
pending = true;
pendingQueue.pop_front();
@@ -200,26 +207,34 @@ TableWalker::processWalkWrapper()
// squashed we shouldn't bother.
unsigned num_squashed = 0;
ThreadContext *tc = currState->tc;
- assert(currState->transState->squashed());
while ((num_squashed < numSquashable) && currState &&
- currState->transState->squashed()) {
+ (currState->transState->squashed() || te)) {
pendingQueue.pop_front();
num_squashed++;
DPRINTF(TLB, "Squashing table walk for address %#x\n", currState->vaddr);
- // finish the translation which will delete the translation object
- currState->transState->finish(new UnimpFault("Squashed Inst"),
- currState->req, currState->tc, currState->mode);
+ if (currState->transState->squashed()) {
+ // finish the translation which will delete the translation object
+ currState->transState->finish(new UnimpFault("Squashed Inst"),
+ currState->req, currState->tc, currState->mode);
+ } else {
+ // translate the request now that we know it will work
+ currState->fault = tlb->translateTiming(currState->req, currState->tc,
+ currState->transState, currState->mode);
+ }
// delete the current request
delete currState;
// peak at the next one
- if (pendingQueue.size())
+ if (pendingQueue.size()) {
currState = pendingQueue.front();
- else
+ te = tlb->lookup(currState->vaddr, currState->contextId, true);
+ } else {
+ // Terminate the loop, nothing more to do
currState = NULL;
+ }
}
// if we've still got pending translations schedule more work