arm: fix a page table walker issue where a page could be translated multiple times
If multiple memory operations to the same page are miss the TLB they are all inserted into the page table queue and before this change could result in multiple uncessesary walks as well as duplicate enteries being inserted into the TLB.
This commit is contained in:
parent
3af59ab386
commit
8cef39fb67
3 changed files with 32 additions and 17 deletions
|
@ -186,8 +186,15 @@ TableWalker::processWalkWrapper()
|
||||||
assert(pendingQueue.size());
|
assert(pendingQueue.size());
|
||||||
currState = pendingQueue.front();
|
currState = pendingQueue.front();
|
||||||
|
|
||||||
|
// Check if a previous walk filled this request already
|
||||||
|
TlbEntry* te = tlb->lookup(currState->vaddr, currState->contextId, true);
|
||||||
|
|
||||||
if (!currState->transState->squashed()) {
|
// 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
|
// We've got a valid request, lets process it
|
||||||
pending = true;
|
pending = true;
|
||||||
pendingQueue.pop_front();
|
pendingQueue.pop_front();
|
||||||
|
@ -200,26 +207,34 @@ TableWalker::processWalkWrapper()
|
||||||
// squashed we shouldn't bother.
|
// squashed we shouldn't bother.
|
||||||
unsigned num_squashed = 0;
|
unsigned num_squashed = 0;
|
||||||
ThreadContext *tc = currState->tc;
|
ThreadContext *tc = currState->tc;
|
||||||
assert(currState->transState->squashed());
|
|
||||||
while ((num_squashed < numSquashable) && currState &&
|
while ((num_squashed < numSquashable) && currState &&
|
||||||
currState->transState->squashed()) {
|
(currState->transState->squashed() || te)) {
|
||||||
pendingQueue.pop_front();
|
pendingQueue.pop_front();
|
||||||
num_squashed++;
|
num_squashed++;
|
||||||
|
|
||||||
DPRINTF(TLB, "Squashing table walk for address %#x\n", currState->vaddr);
|
DPRINTF(TLB, "Squashing table walk for address %#x\n", currState->vaddr);
|
||||||
|
|
||||||
// finish the translation which will delete the translation object
|
if (currState->transState->squashed()) {
|
||||||
currState->transState->finish(new UnimpFault("Squashed Inst"),
|
// finish the translation which will delete the translation object
|
||||||
currState->req, currState->tc, currState->mode);
|
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 the current request
|
||||||
delete currState;
|
delete currState;
|
||||||
|
|
||||||
// peak at the next one
|
// peak at the next one
|
||||||
if (pendingQueue.size())
|
if (pendingQueue.size()) {
|
||||||
currState = pendingQueue.front();
|
currState = pendingQueue.front();
|
||||||
else
|
te = tlb->lookup(currState->vaddr, currState->contextId, true);
|
||||||
|
} else {
|
||||||
|
// Terminate the loop, nothing more to do
|
||||||
currState = NULL;
|
currState = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we've still got pending translations schedule more work
|
// if we've still got pending translations schedule more work
|
||||||
|
|
|
@ -107,7 +107,7 @@ TLB::lookup(Addr va, uint8_t cid, bool functional)
|
||||||
if (table[x].match(va, cid)) {
|
if (table[x].match(va, cid)) {
|
||||||
|
|
||||||
// We only move the hit entry ahead when the position is higher than rangeMRU
|
// We only move the hit entry ahead when the position is higher than rangeMRU
|
||||||
if (x > rangeMRU) {
|
if (x > rangeMRU && !functional) {
|
||||||
TlbEntry tmp_entry = table[x];
|
TlbEntry tmp_entry = table[x];
|
||||||
for(int i = x; i > 0; i--)
|
for(int i = x; i > 0; i--)
|
||||||
table[i] = table[i-1];
|
table[i] = table[i-1];
|
||||||
|
|
|
@ -91,14 +91,6 @@ class TLB : public BaseTLB
|
||||||
|
|
||||||
TableWalker *tableWalker;
|
TableWalker *tableWalker;
|
||||||
|
|
||||||
/** Lookup an entry in the TLB
|
|
||||||
* @param vpn virtual address
|
|
||||||
* @param asn context id/address space id to use
|
|
||||||
* @param functional if the lookup should modify state
|
|
||||||
* @return pointer to TLB entrry if it exists
|
|
||||||
*/
|
|
||||||
TlbEntry *lookup(Addr vpn, uint8_t asn, bool functional = false);
|
|
||||||
|
|
||||||
// Access Stats
|
// Access Stats
|
||||||
mutable Stats::Scalar instHits;
|
mutable Stats::Scalar instHits;
|
||||||
mutable Stats::Scalar instMisses;
|
mutable Stats::Scalar instMisses;
|
||||||
|
@ -132,6 +124,14 @@ class TLB : public BaseTLB
|
||||||
typedef ArmTLBParams Params;
|
typedef ArmTLBParams Params;
|
||||||
TLB(const Params *p);
|
TLB(const Params *p);
|
||||||
|
|
||||||
|
/** Lookup an entry in the TLB
|
||||||
|
* @param vpn virtual address
|
||||||
|
* @param asn context id/address space id to use
|
||||||
|
* @param functional if the lookup should modify state
|
||||||
|
* @return pointer to TLB entrry if it exists
|
||||||
|
*/
|
||||||
|
TlbEntry *lookup(Addr vpn, uint8_t asn, bool functional = false);
|
||||||
|
|
||||||
virtual ~TLB();
|
virtual ~TLB();
|
||||||
int getsize() const { return size; }
|
int getsize() const { return size; }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue