summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mem/cache/cache.cc86
-rw-r--r--src/mem/cache/cache.hh7
-rw-r--r--src/mem/coherent_xbar.cc20
3 files changed, 79 insertions, 34 deletions
diff --git a/src/mem/cache/cache.cc b/src/mem/cache/cache.cc
index 19d8dc800..5ca17b88d 100644
--- a/src/mem/cache/cache.cc
+++ b/src/mem/cache/cache.cc
@@ -455,6 +455,39 @@ Cache::doWritebacks(PacketList& writebacks, Tick forward_time)
}
}
+void
+Cache::doWritebacksAtomic(PacketList& writebacks)
+{
+ while (!writebacks.empty()) {
+ PacketPtr wbPkt = writebacks.front();
+ // Call isCachedAbove for both Writebacks and CleanEvicts. If
+ // isCachedAbove returns true we set BLOCK_CACHED flag in Writebacks
+ // and discard CleanEvicts.
+ if (isCachedAbove(wbPkt, false)) {
+ if (wbPkt->cmd == MemCmd::Writeback) {
+ // Set BLOCK_CACHED flag in Writeback and send below,
+ // so that the Writeback does not reset the bit
+ // corresponding to this address in the snoop filter
+ // below. We can discard CleanEvicts because cached
+ // copies exist above. Atomic mode isCachedAbove
+ // modifies packet to set BLOCK_CACHED flag
+ memSidePort->sendAtomic(wbPkt);
+ }
+ } else {
+ // If the block is not cached above, send packet below. Both
+ // CleanEvict and Writeback with BLOCK_CACHED flag cleared will
+ // reset the bit corresponding to this address in the snoop filter
+ // below.
+ memSidePort->sendAtomic(wbPkt);
+ }
+ writebacks.pop_front();
+ // In case of CleanEvicts, the packet destructor will delete the
+ // request object because this is a non-snoop request packet which
+ // does not require a response.
+ delete wbPkt;
+ }
+}
+
void
Cache::recvTimingSnoopResp(PacketPtr pkt)
@@ -953,12 +986,7 @@ Cache::recvAtomic(PacketPtr pkt)
// handle writebacks resulting from the access here to ensure they
// logically proceed anything happening below
- while (!writebacks.empty()){
- PacketPtr wbPkt = writebacks.front();
- memSidePort->sendAtomic(wbPkt);
- writebacks.pop_front();
- delete wbPkt;
- }
+ doWritebacksAtomic(writebacks);
if (!satisfied) {
// MISS
@@ -1040,12 +1068,7 @@ Cache::recvAtomic(PacketPtr pkt)
// there).
// Handle writebacks (from the response handling) if needed
- while (!writebacks.empty()){
- PacketPtr wbPkt = writebacks.front();
- memSidePort->sendAtomic(wbPkt);
- writebacks.pop_front();
- delete wbPkt;
- }
+ doWritebacksAtomic(writebacks);
if (pkt->needsResponse()) {
pkt->makeAtomicResponse();
@@ -1906,7 +1929,7 @@ Cache::recvTimingSnoopReq(PacketPtr pkt)
// Snoops shouldn't happen when bypassing caches
assert(!system->bypassCaches());
- // no need to snoop writebacks or requests that are not in range
+ // no need to snoop requests that are not in range
if (!inRange(pkt->getAddr())) {
return;
}
@@ -2044,11 +2067,8 @@ Cache::recvAtomicSnoop(PacketPtr pkt)
// Snoops shouldn't happen when bypassing caches
assert(!system->bypassCaches());
- // no need to snoop writebacks or requests that are not in range. In
- // atomic we have no Writebacks/CleanEvicts queued and no prefetches,
- // hence there is no need to snoop upwards and determine if they are
- // present above.
- if (pkt->evictingBlock() || !inRange(pkt->getAddr())) {
+ // no need to snoop requests that are not in range.
+ if (!inRange(pkt->getAddr())) {
return 0;
}
@@ -2144,7 +2164,7 @@ Cache::getNextMSHR()
}
bool
-Cache::isCachedAbove(const PacketPtr pkt) const
+Cache::isCachedAbove(PacketPtr pkt, bool is_timing) const
{
if (!forwardSnoops)
return false;
@@ -2153,18 +2173,22 @@ Cache::isCachedAbove(const PacketPtr pkt) const
// same block. Using the BLOCK_CACHED flag with the Writeback/CleanEvict
// packet, the cache can inform the crossbar below of presence or absence
// of the block.
-
- Packet snoop_pkt(pkt, true, false);
- snoop_pkt.setExpressSnoop();
- // Assert that packet is either Writeback or CleanEvict and not a prefetch
- // request because prefetch requests need an MSHR and may generate a snoop
- // response.
- assert(pkt->evictingBlock());
- snoop_pkt.senderState = NULL;
- cpuSidePort->sendTimingSnoopReq(&snoop_pkt);
- // Writeback/CleanEvict snoops do not generate a separate snoop response.
- assert(!(snoop_pkt.memInhibitAsserted()));
- return snoop_pkt.isBlockCached();
+ if (is_timing) {
+ Packet snoop_pkt(pkt, true, false);
+ snoop_pkt.setExpressSnoop();
+ // Assert that packet is either Writeback or CleanEvict and not a
+ // prefetch request because prefetch requests need an MSHR and may
+ // generate a snoop response.
+ assert(pkt->evictingBlock());
+ snoop_pkt.senderState = NULL;
+ cpuSidePort->sendTimingSnoopReq(&snoop_pkt);
+ // Writeback/CleanEvict snoops do not generate a snoop response.
+ assert(!(snoop_pkt.memInhibitAsserted()));
+ return snoop_pkt.isBlockCached();
+ } else {
+ cpuSidePort->sendAtomicSnoop(pkt);
+ return pkt->isBlockCached();
+ }
}
PacketPtr
diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh
index 577eab664..26c9637f0 100644
--- a/src/mem/cache/cache.hh
+++ b/src/mem/cache/cache.hh
@@ -252,6 +252,11 @@ class Cache : public BaseCache
void doWritebacks(PacketList& writebacks, Tick forward_time);
/**
+ * Send writebacks down the memory hierarchy in atomic mode
+ */
+ void doWritebacksAtomic(PacketList& writebacks);
+
+ /**
* Handles a response (cache line fill/write ack) from the bus.
* @param pkt The response packet
*/
@@ -375,7 +380,7 @@ class Cache : public BaseCache
* Send up a snoop request and find cached copies. If cached copies are
* found, set the BLOCK_CACHED flag in pkt.
*/
- bool isCachedAbove(const PacketPtr pkt) const;
+ bool isCachedAbove(PacketPtr pkt, bool is_timing = true) const;
/**
* Selects an outstanding request to service. Called when the
diff --git a/src/mem/coherent_xbar.cc b/src/mem/coherent_xbar.cc
index b07356ede..7181cb965 100644
--- a/src/mem/coherent_xbar.cc
+++ b/src/mem/coherent_xbar.cc
@@ -605,6 +605,13 @@ CoherentXBar::recvAtomic(PacketPtr pkt, PortID slave_port_id)
" SF size: %i lat: %i\n", __func__,
slavePorts[slave_port_id]->name(), pkt->cmdString(),
pkt->getAddr(), sf_res.first.size(), sf_res.second);
+
+ // let the snoop filter know about the success of the send
+ // operation, and do it even before sending it onwards to
+ // avoid situations where atomic upward snoops sneak in
+ // between and change the filter state
+ snoopFilter->updateRequest(pkt, *slavePorts[slave_port_id], false);
+
snoop_result = forwardAtomic(pkt, slave_port_id, InvalidPortID,
sf_res.first);
} else {
@@ -614,6 +621,15 @@ CoherentXBar::recvAtomic(PacketPtr pkt, PortID slave_port_id)
snoop_response_latency += snoop_result.second;
}
+ // forwardAtomic snooped into peer caches of the sender, and if
+ // this is a clean evict, but the packet is found in a cache, do
+ // not forward it
+ if (pkt->cmd == MemCmd::CleanEvict && pkt->isBlockCached()) {
+ DPRINTF(CoherentXBar, "recvAtomic: Clean evict 0x%x still cached, "
+ "not forwarding\n", pkt->getAddr());
+ return 0;
+ }
+
// even if we had a snoop response, we must continue and also
// perform the actual request at the destination
PortID master_port_id = findPort(pkt->getAddr());
@@ -626,8 +642,8 @@ CoherentXBar::recvAtomic(PacketPtr pkt, PortID slave_port_id)
// forward the request to the appropriate destination
Tick response_latency = masterPorts[master_port_id]->sendAtomic(pkt);
- // Lower levels have replied, tell the snoop filter
- if (snoopFilter && !system->bypassCaches() && pkt->isResponse()) {
+ // if lower levels have replied, tell the snoop filter
+ if (!system->bypassCaches() && snoopFilter && pkt->isResponse()) {
snoopFilter->updateResponse(pkt, *slavePorts[slave_port_id]);
}