Mem: Fix issue with prefetches originating at non-L1 caches getting stale data
authorAli Saidi <Ali.Saidi@ARM.com>
Fri, 15 Jul 2011 16:53:35 +0000 (11:53 -0500)
committerAli Saidi <Ali.Saidi@ARM.com>
Fri, 15 Jul 2011 16:53:35 +0000 (11:53 -0500)
Prefetch requests issued from the L2 or below wouldn't check if valid data is
present higher in the system. If a prefetch into the L2 occured at the same
time as writeback from a higher-level cache the dirty data could be replaced
in by unmodified data in memory.

src/mem/cache/cache_impl.hh

index d4a969d9b2dcd209453805a20b005d04228e9d6e..e1aed8b0c17df73f1d3503ae98d0e29cb0584b62 100644 (file)
@@ -420,7 +420,17 @@ Cache<TagStore>::timingAccess(PacketPtr pkt)
         // must be cache-to-cache response from upper to lower level
         ForwardResponseRecord *rec =
             dynamic_cast<ForwardResponseRecord *>(pkt->senderState);
-        assert(rec != NULL);
+
+        if (rec == NULL) {
+            assert(pkt->cmd == MemCmd::HardPFResp);
+            // Check if it's a prefetch response and handle it. We shouldn't
+            // get any other kinds of responses without FRRs.
+            DPRINTF(Cache, "Got prefetch response from above for addr %#x\n",
+                    pkt->getAddr());
+            handleResponse(pkt);
+            return true;
+        }
+
         rec->restore(pkt, this);
         delete rec;
         memSidePort->respond(pkt, time);
@@ -1472,6 +1482,33 @@ Cache<TagStore>::getTimingPacket()
         pkt = tgt_pkt;
     } else {
         BlkType *blk = tags->findBlock(mshr->addr);
+
+        if (tgt_pkt->cmd == MemCmd::HardPFReq) {
+            // It might be possible for a writeback to arrive between
+            // the time the prefetch is placed in the MSHRs and when
+            // it's selected to send... if so, this assert will catch
+            // that, and then we'll have to figure out what to do.
+            assert(blk == NULL);
+
+            // We need to check the caches above us to verify that they don't have
+            // a copy of this block in the dirty state at the moment. Without this
+            // check we could get a stale copy from memory  that might get used
+            // in place of the dirty one.
+            PacketPtr snoop_pkt = new Packet(tgt_pkt, true);
+            snoop_pkt->setExpressSnoop();
+            snoop_pkt->senderState = mshr;
+            cpuSidePort->sendTiming(snoop_pkt);
+
+            if (snoop_pkt->memInhibitAsserted()) {
+                markInService(mshr, snoop_pkt);
+                DPRINTF(Cache, "Upward snoop of prefetch for addr %#x hit\n",
+                        tgt_pkt->getAddr());
+                delete snoop_pkt;
+                return NULL;
+            }
+            delete snoop_pkt;
+        }
+
         pkt = getBusPacket(tgt_pkt, blk, mshr->needsExclusive());
 
         mshr->isForward = (pkt == NULL);