summaryrefslogtreecommitdiff
path: root/src/mem/cache
diff options
context:
space:
mode:
authorAli Saidi <Ali.Saidi@ARM.com>2011-07-15 11:53:35 -0500
committerAli Saidi <Ali.Saidi@ARM.com>2011-07-15 11:53:35 -0500
commit147095cb0886a962620e60b6950a68931fbd734a (patch)
treeb81211a4e2441c897149b4823506a60f49966a79 /src/mem/cache
parent69ef57fd0f226af90faf46ac877343b5493df693 (diff)
downloadgem5-147095cb0886a962620e60b6950a68931fbd734a.tar.xz
Mem: Fix issue with prefetches originating at non-L1 caches getting stale data
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.
Diffstat (limited to 'src/mem/cache')
-rw-r--r--src/mem/cache/cache_impl.hh39
1 files changed, 38 insertions, 1 deletions
diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh
index d4a969d9b..e1aed8b0c 100644
--- a/src/mem/cache/cache_impl.hh
+++ b/src/mem/cache/cache_impl.hh
@@ -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);