From 147095cb0886a962620e60b6950a68931fbd734a Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Fri, 15 Jul 2011 11:53:35 -0500 Subject: 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. --- src/mem/cache/cache_impl.hh | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'src/mem/cache') 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::timingAccess(PacketPtr pkt) // must be cache-to-cache response from upper to lower level ForwardResponseRecord *rec = dynamic_cast(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::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); -- cgit v1.2.3