diff options
Diffstat (limited to 'src/mem')
-rw-r--r-- | src/mem/cache/cache_impl.hh | 45 | ||||
-rw-r--r-- | src/mem/cache/mshr.cc | 28 | ||||
-rw-r--r-- | src/mem/cache/mshr.hh | 18 | ||||
-rw-r--r-- | src/mem/cache/mshr_queue.cc | 3 | ||||
-rw-r--r-- | src/mem/dram_ctrl.cc | 2 | ||||
-rw-r--r-- | src/mem/simple_mem.cc | 5 |
6 files changed, 87 insertions, 14 deletions
diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh index 24e3eec15..66abf6eff 100644 --- a/src/mem/cache/cache_impl.hh +++ b/src/mem/cache/cache_impl.hh @@ -345,7 +345,6 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, blk->status |= BlkSecure; } } - std::memcpy(blk->data, pkt->getPtr<uint8_t>(), blkSize); if (pkt->cmd == MemCmd::Writeback) { blk->status |= BlkDirty; if (pkt->isSupplyExclusive()) { @@ -354,11 +353,11 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, // nothing else to do; writeback doesn't expect response assert(!pkt->needsResponse()); } else if (pkt->cmd == MemCmd::WriteInvalidateReq) { - assert(blk->isReadable()); // implicitly checks for Valid bit also - blk->status |= (BlkDirty | BlkCanGoExclusive); + blk->status |= (BlkReadable | BlkDirty | BlkCanGoExclusive); blk->status &= ~BlkWritable; ++fastWrites; } + std::memcpy(blk->data, pkt->getPtr<uint8_t>(), blkSize); DPRINTF(Cache, "%s new state is %s\n", __func__, blk->print()); incHitCount(pkt); return true; @@ -636,7 +635,20 @@ Cache<TagStore>::recvTimingReq(PacketPtr pkt) pkt = pf; } - if (mshr) { + if (pkt && (pkt->cmd == MemCmd::WriteInvalidateReq)) { + // WriteInvalidates cannot coalesce with other requests, so + // we cannot use an existing MSHR. If one exists, we mark it + // as 'obsolete' so they don't modify the cache. + if (mshr) { + // Everything up to this point is obsolete, meaning + // they should not modify the cache. + DPRINTF(Cache, "%s: marking MSHR obsolete in %s of %x\n", + __func__, pkt->cmdString(), pkt->getAddr()); + + mshr->markObsolete(); + } + allocateMissBuffer(pkt, time, true); + } else if (mshr) { /// MSHR hit /// @note writebacks will be checked in getNextMSHR() /// for any conflicting requests to the same block @@ -1077,7 +1089,10 @@ Cache<TagStore>::recvTimingResp(PacketPtr pkt) bool is_fill = !mshr->isForward && (pkt->isRead() || pkt->cmd == MemCmd::UpgradeResp); - if (is_fill && !is_error) { + if (mshr->isObsolete()) { + DPRINTF(Cache, "%s: skipping cache fills; data for %s of %x " + "is obsolete\n", __func__, pkt->cmdString(), pkt->getAddr()); + } else if (is_fill && !is_error) { DPRINTF(Cache, "Block for addr %x being updated in Cache\n", pkt->getAddr()); @@ -1113,8 +1128,19 @@ Cache<TagStore>::recvTimingResp(PacketPtr pkt) } if (is_fill) { - satisfyCpuSideRequest(target->pkt, blk, - true, mshr->hasPostDowngrade()); + // Presently the only situation leading to 'obsolete' + // data is when a WriteInvalidate blows away an already + // pending/in-progress read. We don't want to overwrite + // cache data in that case. + if (mshr->isObsolete()) { + DPRINTF(Cache, "%s: skipping satisfyCpuSideRequest; " + "data for %s of %x is obsolete\n", + __func__, target->pkt->cmdString(), + target->pkt->getAddr()); + } else { + satisfyCpuSideRequest(target->pkt, blk, + true, mshr->hasPostDowngrade()); + } // How many bytes past the first request is this one int transfer_offset = target->pkt->getOffset(blkSize) - initial_offset; @@ -1490,6 +1516,11 @@ Cache<TagStore>::handleFill(PacketPtr pkt, BlkType *blk, // there are cases (such as failed store conditionals or // compare-and-swaps) where we'll demand an exclusive copy but // end up not writing it. + // Caveat: if a Read takes a value from a WriteInvalidate MSHR, + // it will get marked Dirty even though it is Clean (once the + // WriteInvalidate completes). This is due to insufficient meta- + // data and overly presumptive interpretation of the inhibit flag. + // The result is an unnecessary extra writeback. if (pkt->memInhibitAsserted()) blk->status |= BlkDirty; } diff --git a/src/mem/cache/mshr.cc b/src/mem/cache/mshr.cc index 79a91da2b..bc46ed267 100644 --- a/src/mem/cache/mshr.cc +++ b/src/mem/cache/mshr.cc @@ -62,10 +62,11 @@ using namespace std; MSHR::MSHR() : readyTime(0), _isUncacheable(false), downstreamPending(false), - pendingDirty(false), postInvalidate(false), - postDowngrade(false), queue(NULL), order(0), addr(0), size(0), - isSecure(false), inService(false), isForward(false), - threadNum(InvalidThreadID), data(NULL) + pendingDirty(false), pendingClean(false), + postInvalidate(false), postDowngrade(false), + _isObsolete(false), queue(NULL), order(0), addr(0), + size(0), isSecure(false), inService(false), + isForward(false), threadNum(InvalidThreadID), data(NULL) { } @@ -213,7 +214,9 @@ MSHR::allocate(Addr _addr, int _size, PacketPtr target, Tick whenReady, isForward = false; _isUncacheable = target->req->isUncacheable(); inService = false; + pendingClean = (target->cmd == MemCmd::WriteInvalidateReq); downstreamPending = false; + _isObsolete = false; threadNum = 0; assert(targets.isReset()); // Don't know of a case where we would allocate a new MSHR for a @@ -250,7 +253,8 @@ MSHR::markInService(PacketPtr pkt) assert(pkt != NULL); inService = true; - pendingDirty = (targets.needsExclusive || + pendingDirty = ((targets.needsExclusive && + (pkt->cmd != MemCmd::WriteInvalidateReq)) || (!pkt->sharedAsserted() && pkt->memInhibitAsserted())); postInvalidate = postDowngrade = false; @@ -366,7 +370,12 @@ MSHR::handleSnoop(PacketPtr pkt, Counter _order) targets.add(cp_pkt, curTick(), _order, Target::FromSnoop, downstreamPending && targets.needsExclusive); - if (isPendingDirty()) { + // WriteInvalidates must writeback and should not be inhibited on + // account of its snoops discovering MSHRs wanting exclusive access + // to what it wrote. We don't want to push this check higher, + // however, because we want to be sure to add an invalidating + // Target::FromSnoop, above. + if (isPendingDirty() && (pkt->cmd != MemCmd::WriteInvalidateReq)) { pkt->assertMemInhibit(); pkt->setSupplyExclusive(); } @@ -374,6 +383,13 @@ MSHR::handleSnoop(PacketPtr pkt, Counter _order) if (pkt->needsExclusive()) { // This transaction will take away our pending copy postInvalidate = true; + + // Do not defer (i.e. return true) the snoop if the block is + // going to be clean once the MSHR completes, as the data is + // ready now. + if (isPendingClean()) { + return false; + } } } diff --git a/src/mem/cache/mshr.hh b/src/mem/cache/mshr.hh index 65357b9e6..e5a15b61d 100644 --- a/src/mem/cache/mshr.hh +++ b/src/mem/cache/mshr.hh @@ -83,12 +83,18 @@ class MSHR : public Packet::SenderState, public Printable /** Will we have a dirty copy after this request? */ bool pendingDirty; + /** Will we have a clean copy after this request? (i.e. is writeback) */ + bool pendingClean; + /** Did we snoop an invalidate while waiting for data? */ bool postInvalidate; /** Did we snoop a read while waiting for data? */ bool postDowngrade; + /** Did we get WriteInvalidate'd (and therefore obsoleted)? */ + bool _isObsolete; + public: class Target { @@ -176,6 +182,10 @@ class MSHR : public Packet::SenderState, public Printable assert(inService); return pendingDirty; } + bool isPendingClean() const { + return pendingClean; + } + bool hasPostInvalidate() const { assert(inService); return postInvalidate; } @@ -214,6 +224,8 @@ class MSHR : public Packet::SenderState, public Printable bool isUncacheable() const { return _isUncacheable; } + bool isObsolete() const { return _isObsolete; } + /** * Allocate a miss to this MSHR. * @param cmd The requesting command. @@ -289,6 +301,12 @@ class MSHR : public Packet::SenderState, public Printable bool checkFunctional(PacketPtr pkt); + /** Mark this MSHR as tracking a transaction with obsoleted data. It still + * needs to complete its lifecycle, but should not modify the cache. */ + void markObsolete() { + _isObsolete = true; + } + /** * Prints the contents of this MSHR for debugging. */ diff --git a/src/mem/cache/mshr_queue.cc b/src/mem/cache/mshr_queue.cc index 7bfbb90f5..9146cddf7 100644 --- a/src/mem/cache/mshr_queue.cc +++ b/src/mem/cache/mshr_queue.cc @@ -45,7 +45,9 @@ * Definition of MSHRQueue class functions. */ +#include "base/trace.hh" #include "mem/cache/mshr_queue.hh" +#include "debug/Drain.hh" using namespace std; @@ -191,6 +193,7 @@ MSHRQueue::deallocateOne(MSHR *mshr) if (drainManager && allocated == 0) { // Notify the drain manager that we have completed draining if // there are no other outstanding requests in this MSHR queue. + DPRINTF(Drain, "MSHRQueue now empty, signalling drained\n"); drainManager->signalDrainDone(); drainManager = NULL; setDrainState(Drainable::Drained); diff --git a/src/mem/dram_ctrl.cc b/src/mem/dram_ctrl.cc index f65f7e1dd..1beebdd01 100644 --- a/src/mem/dram_ctrl.cc +++ b/src/mem/dram_ctrl.cc @@ -737,6 +737,7 @@ DRAMCtrl::processRespondEvent() // if there is nothing left in any queue, signal a drain if (writeQueue.empty() && readQueue.empty() && drainManager) { + DPRINTF(Drain, "DRAM controller done draining\n"); drainManager->signalDrainDone(); drainManager = NULL; } @@ -1290,6 +1291,7 @@ DRAMCtrl::processNextReqEvent() } else { // check if we are drained if (respQueue.empty () && drainManager) { + DPRINTF(Drain, "DRAM controller done draining\n"); drainManager->signalDrainDone(); drainManager = NULL; } diff --git a/src/mem/simple_mem.cc b/src/mem/simple_mem.cc index 27d3f1186..4e1020de5 100644 --- a/src/mem/simple_mem.cc +++ b/src/mem/simple_mem.cc @@ -44,6 +44,7 @@ #include "base/random.hh" #include "mem/simple_mem.hh" +#include "debug/Drain.hh" using namespace std; @@ -200,6 +201,7 @@ SimpleMemory::dequeue() reschedule(dequeueEvent, std::max(packetQueue.front().tick, curTick()), true); } else if (drainManager) { + DPRINTF(Drain, "Drainng of SimpleMemory complete\n"); drainManager->signalDrainDone(); drainManager = NULL; } @@ -240,7 +242,8 @@ SimpleMemory::drain(DrainManager *dm) if (!packetQueue.empty()) { count += 1; drainManager = dm; - } + DPRINTF(Drain, "SimpleMemory Queue has requests, waiting to drain\n"); + } if (count) setDrainState(Drainable::Draining); |