mem: Fix prefetchSquash + memInhibitAsserted bug
authorAli Jafri <ali.jafri@arm.com>
Mon, 2 Mar 2015 09:00:34 +0000 (04:00 -0500)
committerAli Jafri <ali.jafri@arm.com>
Mon, 2 Mar 2015 09:00:34 +0000 (04:00 -0500)
This patch resolves a bug with hardware prefetches. Before a hardware prefetch
is sent towards the memory, the system generates a snoop request to check all
caches above the prefetch generating cache for the presence of the prefetth
target. If the prefetch target is found in the tags or the MSHRs of the upper
caches, the cache sets the prefetchSquashed flag in the snoop packet. When the
snoop packet returns with the prefetchSquashed flag set, the prefetch
generating cache deallocates the MSHR reserved for the prefetch. If the
prefetch target is found in the writeback buffer of the upper cache, the cache
sets the memInhibit flag, which signals the prefetch generating cache to
expect the data from the writeback. When the snoop packet returns with the
memInhibitAsserted flag set, it marks the allocated MSHR as inService and
waits for the data from the writeback.

If the prefetch target is found in multiple upper level caches, specifically
in the tags or MSHRs of one upper level cache and the writeback buffer of
another, the snoop packet will return with both prefetchSquashed and
memInhibitAsserted set, while the current code is not written to handle such
an outcome. Current code checks for the prefetchSquashed flag first, if it
finds the flag, it deallocates the reserved MSHR. This leads to assert failure
when the data from the writeback appears at cache. In this fix, we simply
switch the order of checks. We first check for memInhibitAsserted and then for
prefetch squashed.

src/mem/cache/cache_impl.hh

index 29285abce3ef664d7f3b5e544fddd3606d5d38a2..14e49e1f7ffc4d4717bc7ff21f08f302639e21d9 100644 (file)
@@ -1966,10 +1966,28 @@ Cache<TagStore>::getTimingPacket()
             snoop_pkt.senderState = mshr;
             cpuSidePort->sendTimingSnoopReq(&snoop_pkt);
 
-            // Check to see if the prefetch was squashed by an upper
-            // cache (to prevent us from grabbing the line) or if a
-            // writeback arrived between the time the prefetch was
-            // placed in the MSHRs and when it was selected to be sent.
+            // Check to see if the prefetch was squashed by an upper cache (to
+            // prevent us from grabbing the line) or if a Check to see if a
+            // writeback arrived between the time the prefetch was placed in
+            // the MSHRs and when it was selected to be sent or if the
+            // prefetch was squashed by an upper cache.
+
+            // It is important to check msmInhibitAsserted before
+            // prefetchSquashed. If another cache has asserted MEM_INGIBIT, it
+            // will be sending a response which will arrive at the MSHR
+            // allocated ofr this request. Checking the prefetchSquash first
+            // may result in the MSHR being prematurely deallocated.
+
+            if (snoop_pkt.memInhibitAsserted()) {
+                // If we are getting a non-shared response it is dirty
+                bool pending_dirty_resp = !snoop_pkt.sharedAsserted();
+                markInService(mshr, pending_dirty_resp);
+                DPRINTF(Cache, "Upward snoop of prefetch for addr"
+                        " %#x (%s) hit\n",
+                        tgt_pkt->getAddr(), tgt_pkt->isSecure()? "s": "ns");
+                return NULL;
+            }
+
             if (snoop_pkt.prefetchSquashed() || blk != NULL) {
                 DPRINTF(Cache, "Prefetch squashed by cache.  "
                                "Deallocating mshr target %#x.\n", mshr->addr);
@@ -1983,18 +2001,6 @@ Cache<TagStore>::getTimingPacket()
                 return NULL;
             }
 
-            // Check if the prefetch hit a writeback in an upper cache
-            // and if so we will eventually get a HardPFResp from
-            // above
-            if (snoop_pkt.memInhibitAsserted()) {
-                // If we are getting a non-shared response it is dirty
-                bool pending_dirty_resp = !snoop_pkt.sharedAsserted();
-                markInService(mshr, pending_dirty_resp);
-                DPRINTF(Cache, "Upward snoop of prefetch for addr"
-                        " %#x (%s) hit\n",
-                        tgt_pkt->getAddr(), tgt_pkt->isSecure()? "s": "ns");
-                return NULL;
-            }
         }
 
         pkt = getBusPacket(tgt_pkt, blk, mshr->needsExclusive());