mem: Make LL/SC locks fine grained
The current implementation in gem5 just keeps a list of locks per cacheline. Due to this, a store to a non-overlapping portion of the cacheline can cause an LL/SC pair to fail. This patch simply adds an address range to the lock structure, so that the lock is only invalidated if the store overlaps the lock range.
This commit is contained in:
parent
dc4a0aa2fa
commit
c7dbd5e768
41
src/mem/cache/blk.hh
vendored
41
src/mem/cache/blk.hh
vendored
|
@ -127,15 +127,30 @@ class CacheBlk
|
|||
class Lock {
|
||||
public:
|
||||
int contextId; // locking context
|
||||
Addr lowAddr; // low address of lock range
|
||||
Addr highAddr; // high address of lock range
|
||||
|
||||
// check for matching execution context
|
||||
bool matchesContext(Request *req)
|
||||
{
|
||||
return (contextId == req->contextId());
|
||||
Addr req_low = req->getPaddr();
|
||||
Addr req_high = req_low + req->getSize() -1;
|
||||
return (contextId == req->contextId()) &&
|
||||
(req_low >= lowAddr) && (req_high <= highAddr);
|
||||
}
|
||||
|
||||
bool overlapping(Request *req)
|
||||
{
|
||||
Addr req_low = req->getPaddr();
|
||||
Addr req_high = req_low + req->getSize() - 1;
|
||||
|
||||
return (req_low <= highAddr) && (req_high >= lowAddr);
|
||||
}
|
||||
|
||||
Lock(Request *req)
|
||||
: contextId(req->contextId())
|
||||
: contextId(req->contextId()),
|
||||
lowAddr(req->getPaddr()),
|
||||
highAddr(lowAddr + req->getSize() - 1)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
@ -255,7 +270,23 @@ class CacheBlk
|
|||
* Clear the list of valid load locks. Should be called whenever
|
||||
* block is written to or invalidated.
|
||||
*/
|
||||
void clearLoadLocks() { lockList.clear(); }
|
||||
void clearLoadLocks(Request *req = NULL)
|
||||
{
|
||||
if (!req) {
|
||||
// No request, invaldate all locks to this line
|
||||
lockList.clear();
|
||||
} else {
|
||||
// Only invalidate locks that overlap with this request
|
||||
std::list<Lock>::iterator lock_itr = lockList.begin();
|
||||
while (lock_itr != lockList.end()) {
|
||||
if (lock_itr->overlapping(req)) {
|
||||
lock_itr = lockList.erase(lock_itr);
|
||||
} else {
|
||||
++lock_itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle interaction of load-locked operations and stores.
|
||||
|
@ -283,12 +314,12 @@ class CacheBlk
|
|||
}
|
||||
|
||||
req->setExtraData(success ? 1 : 0);
|
||||
clearLoadLocks();
|
||||
clearLoadLocks(req);
|
||||
return success;
|
||||
} else {
|
||||
// for *all* stores (conditional or otherwise) we have to
|
||||
// clear the list of load-locks as they're all invalid now.
|
||||
clearLoadLocks();
|
||||
clearLoadLocks(req);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue