X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmem%2Fcache%2Fmshr.cc;h=5b9302925831ae67751ff64fbbe28d497b9d5f14;hb=338a173e822298bd22741342a7b24352450afdd1;hp=dc490790b1fd871f91533e973de423a768faa192;hpb=56865ad1154c7c3fde2ae6b7329d0c888390f781;p=gem5.git diff --git a/src/mem/cache/mshr.cc b/src/mem/cache/mshr.cc index dc490790b..5b9302925 100644 --- a/src/mem/cache/mshr.cc +++ b/src/mem/cache/mshr.cc @@ -40,6 +40,7 @@ * * Authors: Erik Hallnor * Dave Greene + * Nikos Nikoleris */ /** @@ -63,7 +64,7 @@ MSHR::MSHR() : downstreamPending(false), pendingModified(false), postInvalidate(false), postDowngrade(false), - isForward(false) + wasWholeLineWrite(false), isForward(false) { } @@ -95,6 +96,8 @@ MSHR::TargetList::updateFlags(PacketPtr pkt, Target::Source source, if (source != Target::FromPrefetcher) { hasFromCache = hasFromCache || pkt->fromCache(); + + updateWriteFlags(pkt); } } } @@ -179,31 +182,38 @@ MSHR::TargetList::replaceUpgrades() void -MSHR::TargetList::clearDownstreamPending() +MSHR::TargetList::clearDownstreamPending(MSHR::TargetList::iterator begin, + MSHR::TargetList::iterator end) { - for (auto& t : *this) { - if (t.markedPending) { + for (auto t = begin; t != end; t++) { + if (t->markedPending) { // Iterate over the SenderState stack and see if we find // an MSHR entry. If we find one, clear the // downstreamPending flag by calling // clearDownstreamPending(). This recursively clears the // downstreamPending flag in all caches this packet has // passed through. - MSHR *mshr = t.pkt->findNextSenderState(); + MSHR *mshr = t->pkt->findNextSenderState(); if (mshr != nullptr) { mshr->clearDownstreamPending(); } - t.markedPending = false; + t->markedPending = false; } } } +void +MSHR::TargetList::clearDownstreamPending() +{ + clearDownstreamPending(begin(), end()); +} + bool -MSHR::TargetList::checkFunctional(PacketPtr pkt) +MSHR::TargetList::trySatisfyFunctional(PacketPtr pkt) { for (auto& t : *this) { - if (pkt->checkFunctional(t.pkt)) { + if (pkt->trySatisfyFunctional(t.pkt)) { return true; } } @@ -250,16 +260,19 @@ MSHR::allocate(Addr blk_addr, unsigned blk_size, PacketPtr target, order = _order; assert(target); isForward = false; + wasWholeLineWrite = false; _isUncacheable = target->req->isUncacheable(); inService = false; downstreamPending = false; - assert(targets.isReset()); + + targets.init(blkAddr, blkSize); + deferredTargets.init(blkAddr, blkSize); + // Don't know of a case where we would allocate a new MSHR for a // snoop (mem-side request), so set source according to request here Target::Source source = (target->cmd == MemCmd::HardPFReq) ? Target::FromPrefetcher : Target::FromCPU; targets.add(target, when_ready, _order, source, true, alloc_on_fill); - assert(deferredTargets.isReset()); } @@ -287,6 +300,10 @@ MSHR::markInService(bool pending_modified_resp) // level where it's going to get a response targets.clearDownstreamPending(); } + // if the line is not considered a whole-line write when sent + // downstream, make sure it is also not considered a whole-line + // write when receiving the response, and vice versa + wasWholeLineWrite = isWholeLineWrite(); } @@ -424,7 +441,8 @@ MSHR::handleSnoop(PacketPtr pkt, Counter _order) // the packet and the request as part of handling the deferred // snoop. PacketPtr cp_pkt = will_respond ? new Packet(pkt, true, true) : - new Packet(new Request(*pkt->req), pkt->cmd, blkSize, pkt->id); + new Packet(std::make_shared(*pkt->req), pkt->cmd, + blkSize, pkt->id); if (will_respond) { // we are the ordering point, and will consequently @@ -472,6 +490,7 @@ MSHR::TargetList MSHR::extractServiceableTargets(PacketPtr pkt) { TargetList ready_targets; + ready_targets.init(blkAddr, blkSize); // If the downstream MSHR got an invalidation request then we only // service the first of the FromCPU targets and any other // non-FromCPU target. This way the remaining FromCPU targets @@ -540,6 +559,49 @@ MSHR::promoteDeferredTargets() return true; } +void +MSHR::promoteIf(const std::function& pred) +{ + // if any of the deferred targets were upper-level cache + // requests marked downstreamPending, need to clear that + assert(!downstreamPending); // not pending here anymore + + // find the first target does not satisfy the condition + auto last_it = std::find_if_not(deferredTargets.begin(), + deferredTargets.end(), + pred); + + // for the prefix of the deferredTargets [begin(), last_it) clear + // the downstreamPending flag and move them to the target list + deferredTargets.clearDownstreamPending(deferredTargets.begin(), + last_it); + targets.splice(targets.end(), deferredTargets, + deferredTargets.begin(), last_it); + // We need to update the flags for the target lists after the + // modifications + deferredTargets.populateFlags(); +} + +void +MSHR::promoteReadable() +{ + if (!deferredTargets.empty() && !hasPostInvalidate()) { + // We got a non invalidating response, and we have the block + // but we have deferred targets which are waiting and they do + // not need writable. This can happen if the original request + // was for a cache clean operation and we had a copy of the + // block. Since we serviced the cache clean operation and we + // have the block, there's no need to defer the targets, so + // move them up to the regular target list. + + auto pred = [](Target &t) { + assert(t.source == Target::FromCPU); + return !t.pkt->req->isCacheInvalidate() && + !t.pkt->needsWritable(); + }; + promoteIf(pred); + } +} void MSHR::promoteWritable() @@ -555,29 +617,29 @@ MSHR::promoteWritable() // target list. assert(!targets.needsWritable); targets.needsWritable = true; - // if any of the deferred targets were upper-level cache - // requests marked downstreamPending, need to clear that - assert(!downstreamPending); // not pending here anymore - deferredTargets.clearDownstreamPending(); - // this clears out deferredTargets too - targets.splice(targets.end(), deferredTargets); - deferredTargets.resetFlags(); + + auto pred = [](Target &t) { + assert(t.source == Target::FromCPU); + return !t.pkt->req->isCacheInvalidate(); + }; + + promoteIf(pred); } } bool -MSHR::checkFunctional(PacketPtr pkt) +MSHR::trySatisfyFunctional(PacketPtr pkt) { // For printing, we treat the MSHR as a whole as single entity. // For other requests, we iterate over the individual targets // since that's where the actual data lies. if (pkt->isPrint()) { - pkt->checkFunctional(this, blkAddr, isSecure, blkSize, nullptr); + pkt->trySatisfyFunctional(this, blkAddr, isSecure, blkSize, nullptr); return false; } else { - return (targets.checkFunctional(pkt) || - deferredTargets.checkFunctional(pkt)); + return (targets.trySatisfyFunctional(pkt) || + deferredTargets.trySatisfyFunctional(pkt)); } }