- if (targets->needsExclusive || pkt->needsExclusive()) {
- // actual target device (typ. PhysicalMemory) will delete the
- // packet on reception, so we need to save a copy here
- PacketPtr cp_pkt = new Packet(pkt, true);
- targets->add(cp_pkt, curTick, _order, Target::FromSnoop,
- downstreamPending && targets->needsExclusive);
- ++ntargets;
-
- if (targets->needsExclusive) {
- // We're awaiting an exclusive copy, so ownership is pending.
- // It's up to us to respond once the data arrives.
- pkt->assertMemInhibit();
- pkt->setSupplyExclusive();
- } else {
- // Someone else may respond before we get around to
- // processing this snoop, which means the copied request
- // pointer will no longer be valid
- cp_pkt->req = NULL;
+ if (isPendingModified() || pkt->isInvalidate()) {
+ // We need to save and replay the packet in two cases:
+ // 1. We're awaiting a writable copy (Modified or Exclusive),
+ // so this MSHR is the orgering point, and we need to respond
+ // after we receive data.
+ // 2. It's an invalidation (e.g., UpgradeReq), and we need
+ // to forward the snoop up the hierarchy after the current
+ // transaction completes.
+
+ // Start by determining if we will eventually respond or not,
+ // matching the conditions checked in Cache::handleSnoop
+ bool will_respond = isPendingModified() && pkt->needsResponse() &&
+ !pkt->isClean();
+
+ // The packet we are snooping may be deleted by the time we
+ // actually process the target, and we consequently need to
+ // save a copy here. Clear flags and also allocate new data as
+ // the original packet data storage may have been deleted by
+ // the time we get to process this packet. In the cases where
+ // we are not responding after handling the snoop we also need
+ // to create a copy of the request to be on the safe side. In
+ // the latter case the cache is responsible for deleting both
+ // the packet and the request as part of handling the deferred
+ // snoop.
+ PacketPtr cp_pkt = will_respond ? new Packet(pkt, true, true) :
+ new Packet(std::make_shared<Request>(*pkt->req), pkt->cmd,
+ blkSize, pkt->id);
+
+ if (will_respond) {
+ // we are the ordering point, and will consequently
+ // respond, and depending on whether the packet
+ // needsWritable or not we either pass a Shared line or a
+ // Modified line
+ pkt->setCacheResponding();
+
+ // inform the cache hierarchy that this cache had the line
+ // in the Modified state, even if the response is passed
+ // as Shared (and thus non-writable)
+ pkt->setResponderHadWritable();
+
+ // in the case of an uncacheable request there is no need
+ // to set the responderHadWritable flag, but since the
+ // recipient does not care there is no harm in doing so
+ } else if (isPendingModified() && pkt->isClean()) {
+ // this cache doesn't respond to the clean request, a
+ // destination xbar will respond to this request, but to
+ // do so it needs to know if it should wait for the
+ // WriteCleanReq
+ pkt->setSatisfied();