+void
+MSHR::promoteIf(const std::function<bool (Target &)>& pred)
+{
+ // if any of the deferred targets were upper-level cache
+ // requests marked downstreamPending, need to clear that
+ assert(!downstreamPending); // not pending here anymore
+
+ // find the first target does not satisfy the condition
+ auto last_it = std::find_if_not(deferredTargets.begin(),
+ deferredTargets.end(),
+ pred);
+
+ // for the prefix of the deferredTargets [begin(), last_it) clear
+ // the downstreamPending flag and move them to the target list
+ deferredTargets.clearDownstreamPending(deferredTargets.begin(),
+ last_it);
+ targets.splice(targets.end(), deferredTargets,
+ deferredTargets.begin(), last_it);
+ // We need to update the flags for the target lists after the
+ // modifications
+ deferredTargets.populateFlags();
+}
+
+void
+MSHR::promoteReadable()
+{
+ if (!deferredTargets.empty() && !hasPostInvalidate()) {
+ // We got a non invalidating response, and we have the block
+ // but we have deferred targets which are waiting and they do
+ // not need writable. This can happen if the original request
+ // was for a cache clean operation and we had a copy of the
+ // block. Since we serviced the cache clean operation and we
+ // have the block, there's no need to defer the targets, so
+ // move them up to the regular target list.
+
+ auto pred = [](Target &t) {
+ assert(t.source == Target::FromCPU);
+ return !t.pkt->req->isCacheInvalidate() &&
+ !t.pkt->needsWritable();
+ };
+ promoteIf(pred);
+ }
+}