mem: Align how snoops are handled when hitting writebacks
authorAndreas Hansson <andreas.hansson@arm.com>
Wed, 10 Feb 2016 09:08:24 +0000 (04:08 -0500)
committerAndreas Hansson <andreas.hansson@arm.com>
Wed, 10 Feb 2016 09:08:24 +0000 (04:08 -0500)
This patch unifies the snoop handling in case of hitting writebacks
with how we handle snoops hitting in the tags. As a result, we end up
using the same optimisation as the normal snoops, where we inform the
downstream cache if we encounter a line in Modified (writable and
dirty) state, which enables us to avoid sending out express snoops to
invalidate any Shared copies of the line. A few regressions
consequently change, as some transactions are sunk higher up in the
cache hierarchy.

src/mem/cache/cache.cc

index 294f807ba89df5723ac9a42d4b8b342a8399e6f3..7a5d22ef052465b55c05fe2edb7ef28f4921e1a2 100644 (file)
@@ -2152,48 +2152,34 @@ Cache::recvTimingSnoopReq(PacketPtr pkt)
             return;
         }
 
-        if (wb_pkt->cmd == MemCmd::WritebackDirty) {
-            // we have dirty data, and so will proceed to respond
+        // conceptually writebacks are no different to other blocks in
+        // this cache, so the behaviour is modelled after handleSnoop,
+        // the difference being that instead of querying the block
+        // state to determine if it is dirty and writable, we use the
+        // command and fields of the writeback packet
+        bool respond = wb_pkt->cmd == MemCmd::WritebackDirty &&
+            pkt->needsResponse() && pkt->cmd != MemCmd::InvalidateReq;
+        bool have_writable = !wb_pkt->hasSharers();
+        bool invalidate = pkt->isInvalidate();
+
+        if (!pkt->req->isUncacheable() && pkt->isRead() && !invalidate) {
+            assert(!pkt->needsWritable());
+            pkt->setHasSharers();
+            wb_pkt->setHasSharers();
+        }
+
+        if (respond) {
             pkt->setCacheResponding();
-            if (!pkt->needsWritable()) {
-                // the packet should end up in the Shared state (non
-                // writable) on the completion of the fill
-                pkt->setHasSharers();
-                // similarly, the writeback is no longer passing
-                // writeable (the receiving cache should consider the
-                // block Owned rather than Modified)
-                wb_pkt->setHasSharers();
-            } else {
-                // we need to invalidate our copy. we do that
-                // below.
-                assert(pkt->isInvalidate());
+
+            if (have_writable) {
+                pkt->setResponderHadWritable();
             }
+
             doTimingSupplyResponse(pkt, wb_pkt->getConstPtr<uint8_t>(),
                                    false, false);
-        } else {
-            // on hitting a clean writeback we play it safe and do not
-            // provide a response, the block may be dirty somewhere
-            // else
-            assert(wb_pkt->isCleanEviction());
-            // The cache technically holds the block until the
-            // corresponding message reaches the crossbar
-            // below. Therefore when a snoop encounters a CleanEvict
-            // or WritebackClean message we must call
-            // setHasSharers (just like when it encounters a
-            // Writeback) to avoid the snoop filter prematurely
-            // clearing the holder bit in the crossbar below
-            if (!pkt->needsWritable()) {
-                pkt->setHasSharers();
-                // the writeback is no longer passing writeable (the
-                // receiving cache should consider the block Owned
-                // rather than Modified)
-                wb_pkt->setHasSharers();
-            } else {
-                assert(pkt->isInvalidate());
-            }
         }
 
-        if (pkt->isInvalidate()) {
+        if (invalidate) {
             // Invalidation trumps our writeback... discard here
             // Note: markInService will remove entry from writeback buffer.
             markInService(wb_entry, false);