summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNikos Nikoleris <nikos.nikoleris@arm.com>2016-09-22 13:34:17 +0100
committerNikos Nikoleris <nikos.nikoleris@arm.com>2017-12-05 11:47:01 +0000
commit9a49827a44853679b737b8ee4255ce22d5fbfa6c (patch)
tree663ac71a5d234ffb2dc390401815c170a7e2b46e /src
parent149a501d8a52373d0b9108311d7e64d6376bb45b (diff)
downloadgem5-9a49827a44853679b737b8ee4255ce22d5fbfa6c.tar.xz
mem: Add support for handling CMOs in the MSHRs
To add support for cache maintenance operations (CMOs) in the MSHRs, this change adds the following functionality: - If a CMO request hits in the MSHRs, we deferred as we can't coalesce it with any other requests. - When we promote any deferred targets, we promote them in order and stop if we encounter a CMO request. If the CMO request is at the beginning of the deferred targets list it will be the only promoted target. Change-Id: I10d1f7e16bd6d522d917279c5d408a3f0cee4286 Reviewed-by: Stephan Diestelhorst <stephan.diestelhorst@arm.com> Reviewed-on: https://gem5-review.googlesource.com/5050 Maintainer: Nikos Nikoleris <nikos.nikoleris@arm.com> Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Diffstat (limited to 'src')
-rw-r--r--src/mem/cache/mshr.cc83
1 files changed, 56 insertions, 27 deletions
diff --git a/src/mem/cache/mshr.cc b/src/mem/cache/mshr.cc
index fa21f5cfc..d89adef19 100644
--- a/src/mem/cache/mshr.cc
+++ b/src/mem/cache/mshr.cc
@@ -318,16 +318,24 @@ MSHR::allocateTarget(PacketPtr pkt, Tick whenReady, Counter _order,
// - there are other targets already deferred
// - there's a pending invalidate to be applied after the response
// comes back (but before this target is processed)
+ // - the MSHR's first (and only) non-deferred target is a cache
+ // maintenance packet
+ // - the new target is a cache maintenance packet (this is probably
+ // overly conservative but certainly safe)
// - this target requires a writable block and either we're not
// getting a writable block back or we have already snooped
// another read request that will downgrade our writable block
// to non-writable (Shared or Owned)
- if (inService &&
- (!deferredTargets.empty() || hasPostInvalidate() ||
- (pkt->needsWritable() &&
- (!isPendingModified() || hasPostDowngrade() || isForward)))) {
+ PacketPtr tgt_pkt = targets.front().pkt;
+ if (pkt->req->isCacheMaintenance() ||
+ tgt_pkt->req->isCacheMaintenance() ||
+ !deferredTargets.empty() ||
+ (inService &&
+ (hasPostInvalidate() ||
+ (pkt->needsWritable() &&
+ (!isPendingModified() || hasPostDowngrade() || isForward))))) {
// need to put on deferred list
- if (hasPostInvalidate())
+ if (inService && hasPostInvalidate())
replaceUpgrade(pkt);
deferredTargets.add(pkt, whenReady, _order, Target::FromCPU, true,
alloc_on_fill);
@@ -349,7 +357,8 @@ MSHR::handleSnoop(PacketPtr pkt, Counter _order)
// when we snoop packets the needsWritable and isInvalidate flags
// should always be the same, however, this assumes that we never
// snoop writes as they are currently not marked as invalidations
- panic_if(pkt->needsWritable() != pkt->isInvalidate(),
+ panic_if((pkt->needsWritable() != pkt->isInvalidate()) &&
+ !pkt->req->isCacheMaintenance(),
"%s got snoop %s where needsWritable, "
"does not match isInvalidate", name(), pkt->print());
@@ -367,7 +376,7 @@ MSHR::handleSnoop(PacketPtr pkt, Counter _order)
// That is, even though the upper-level cache got out on its
// local bus first, some other invalidating transaction
// reached the global bus before the upgrade did.
- if (pkt->needsWritable()) {
+ if (pkt->needsWritable() || pkt->req->isCacheInvalidate()) {
targets.replaceUpgrades();
deferredTargets.replaceUpgrades();
}
@@ -377,16 +386,18 @@ MSHR::handleSnoop(PacketPtr pkt, Counter _order)
// From here on down, the request issued by this MSHR logically
// precedes the request we're snooping.
- if (pkt->needsWritable()) {
+ if (pkt->needsWritable() || pkt->req->isCacheInvalidate()) {
// snooped request still precedes the re-request we'll have to
// issue for deferred targets, if any...
deferredTargets.replaceUpgrades();
}
- if (hasPostInvalidate()) {
- // a prior snoop has already appended an invalidation, so
- // logically we don't have the block anymore; no need for
- // further snooping.
+ PacketPtr tgt_pkt = targets.front().pkt;
+ if (hasPostInvalidate() || tgt_pkt->req->isCacheInvalidate()) {
+ // a prior snoop has already appended an invalidation or a
+ // cache invalidation operation is in progress, so logically
+ // we don't have the block anymore; no need for further
+ // snooping.
return true;
}
@@ -401,7 +412,8 @@ MSHR::handleSnoop(PacketPtr pkt, Counter _order)
// Start by determining if we will eventually respond or not,
// matching the conditions checked in Cache::handleSnoop
- bool will_respond = isPendingModified() && pkt->needsResponse();
+ bool will_respond = isPendingModified() && pkt->needsResponse() &&
+ !pkt->isClean();
// The packet we are snooping may be deleted by the time we
// actually process the target, and we consequently need to
@@ -435,10 +447,14 @@ MSHR::handleSnoop(PacketPtr pkt, Counter _order)
targets.add(cp_pkt, curTick(), _order, Target::FromSnoop,
downstreamPending && targets.needsWritable, false);
- if (pkt->needsWritable()) {
+ if (pkt->needsWritable() || pkt->isInvalidate()) {
// This transaction will take away our pending copy
postInvalidate = true;
}
+
+ if (pkt->isClean()) {
+ pkt->setSatisfied();
+ }
}
if (!pkt->needsWritable() && !pkt->req->isUncacheable()) {
@@ -490,23 +506,36 @@ MSHR::extractServiceableTargets(PacketPtr pkt)
bool
MSHR::promoteDeferredTargets()
{
- if (targets.empty()) {
- if (deferredTargets.empty()) {
- return false;
- }
+ if (targets.empty() && deferredTargets.empty()) {
+ // nothing to promote
+ return false;
+ }
- std::swap(targets, deferredTargets);
+ // the deferred targets can be generally promoted unless they
+ // contain a cache maintenance request
+
+ // find the first target that is a cache maintenance request
+ auto it = std::find_if(deferredTargets.begin(), deferredTargets.end(),
+ [](MSHR::Target &t) {
+ return t.pkt->req->isCacheMaintenance();
+ });
+ if (it == deferredTargets.begin()) {
+ // if the first deferred target is a cache maintenance packet
+ // then we can promote provided the targets list is empty and
+ // we can service it on its own
+ if (targets.empty()) {
+ targets.splice(targets.end(), deferredTargets, it);
+ }
} else {
- // If the targets list is not empty then we have one targets
- // from the deferredTargets list to the targets list. A new
- // request will then service the targets list.
- targets.splice(targets.end(), deferredTargets);
- targets.populateFlags();
+ // if a cache maintenance operation exists, we promote all the
+ // deferred targets that precede it, or all deferred targets
+ // otherwise
+ targets.splice(targets.end(), deferredTargets,
+ deferredTargets.begin(), it);
}
- // clear deferredTargets flags
- deferredTargets.resetFlags();
-
+ deferredTargets.populateFlags();
+ targets.populateFlags();
order = targets.front().order;
readyTime = std::max(curTick(), targets.front().readyTime);