mshr.cc revision 11286:2071db8f864b
112854Sgabeblack@google.com/* 212854Sgabeblack@google.com * Copyright (c) 2012-2013, 2015 ARM Limited 312854Sgabeblack@google.com * All rights reserved. 412854Sgabeblack@google.com * 512854Sgabeblack@google.com * The license below extends only to copyright in the software and shall 612854Sgabeblack@google.com * not be construed as granting a license to any other intellectual 712854Sgabeblack@google.com * property including but not limited to intellectual property relating 812854Sgabeblack@google.com * to a hardware implementation of the functionality of the software 912854Sgabeblack@google.com * licensed hereunder. You may use the software subject to the license 1012854Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated 1112854Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software, 1212854Sgabeblack@google.com * modified or unmodified, in source code or in binary form. 1312854Sgabeblack@google.com * 1412854Sgabeblack@google.com * Copyright (c) 2002-2005 The Regents of The University of Michigan 1512854Sgabeblack@google.com * Copyright (c) 2010 Advanced Micro Devices, Inc. 1612854Sgabeblack@google.com * All rights reserved. 1712854Sgabeblack@google.com * 1812854Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 1912854Sgabeblack@google.com * modification, are permitted provided that the following conditions are 2012854Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 2112854Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 2212854Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 2312854Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 2412854Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 2512854Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 2612854Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 2712854Sgabeblack@google.com * this software without specific prior written permission. 2812854Sgabeblack@google.com * 2912854Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3012854Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3112854Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3212854Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3312854Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3412854Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3512854Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3612854Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3712854Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3812854Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3912854Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 4012854Sgabeblack@google.com * 4112854Sgabeblack@google.com * Authors: Erik Hallnor 4212854Sgabeblack@google.com * Dave Greene 4312854Sgabeblack@google.com */ 4412854Sgabeblack@google.com 4512854Sgabeblack@google.com/** 4612854Sgabeblack@google.com * @file 4712854Sgabeblack@google.com * Miss Status and Handling Register (MSHR) definitions. 4812854Sgabeblack@google.com */ 4912854Sgabeblack@google.com 5012854Sgabeblack@google.com#include <algorithm> 5112854Sgabeblack@google.com#include <cassert> 5212854Sgabeblack@google.com#include <string> 5312854Sgabeblack@google.com#include <vector> 5413322Sgabeblack@google.com 5512854Sgabeblack@google.com#include "base/misc.hh" 5612854Sgabeblack@google.com#include "base/types.hh" 5712854Sgabeblack@google.com#include "debug/Cache.hh" 5812854Sgabeblack@google.com#include "mem/cache/cache.hh" 5912854Sgabeblack@google.com#include "mem/cache/mshr.hh" 6012854Sgabeblack@google.com#include "sim/core.hh" 6112854Sgabeblack@google.com 6212854Sgabeblack@google.comusing namespace std; 6312854Sgabeblack@google.com 6412854Sgabeblack@google.comMSHR::MSHR() : readyTime(0), _isUncacheable(false), downstreamPending(false), 6512854Sgabeblack@google.com pendingModified(false), 6612854Sgabeblack@google.com postInvalidate(false), postDowngrade(false), 6712854Sgabeblack@google.com queue(NULL), order(0), blkAddr(0), 6812854Sgabeblack@google.com blkSize(0), isSecure(false), inService(false), 6912854Sgabeblack@google.com isForward(false), allocOnFill(false), 7012854Sgabeblack@google.com data(NULL) 7112854Sgabeblack@google.com{ 7212854Sgabeblack@google.com} 7312854Sgabeblack@google.com 7412854Sgabeblack@google.com 7512854Sgabeblack@google.comMSHR::TargetList::TargetList() 7612854Sgabeblack@google.com : needsWritable(false), hasUpgrade(false) 7712854Sgabeblack@google.com{} 7812854Sgabeblack@google.com 7912854Sgabeblack@google.com 8012854Sgabeblack@google.cominline void 8112854Sgabeblack@google.comMSHR::TargetList::add(PacketPtr pkt, Tick readyTime, 8212854Sgabeblack@google.com Counter order, Target::Source source, bool markPending) 8312854Sgabeblack@google.com{ 8412854Sgabeblack@google.com if (source != Target::FromSnoop) { 8512854Sgabeblack@google.com if (pkt->needsWritable()) { 8612854Sgabeblack@google.com needsWritable = true; 8712854Sgabeblack@google.com } 8812854Sgabeblack@google.com 8912854Sgabeblack@google.com // StoreCondReq is effectively an upgrade if it's in an MSHR 9012854Sgabeblack@google.com // since it would have been failed already if we didn't have a 9112854Sgabeblack@google.com // read-only copy 9212854Sgabeblack@google.com if (pkt->isUpgrade() || pkt->cmd == MemCmd::StoreCondReq) { 9312854Sgabeblack@google.com hasUpgrade = true; 9412854Sgabeblack@google.com } 9512854Sgabeblack@google.com } 9612854Sgabeblack@google.com 9712854Sgabeblack@google.com if (markPending) { 9812854Sgabeblack@google.com // Iterate over the SenderState stack and see if we find 9912854Sgabeblack@google.com // an MSHR entry. If we do, set the downstreamPending 10012854Sgabeblack@google.com // flag. Otherwise, do nothing. 10112854Sgabeblack@google.com MSHR *mshr = pkt->findNextSenderState<MSHR>(); 10212854Sgabeblack@google.com if (mshr != NULL) { 10312854Sgabeblack@google.com assert(!mshr->downstreamPending); 10412854Sgabeblack@google.com mshr->downstreamPending = true; 10512854Sgabeblack@google.com } else { 10612854Sgabeblack@google.com // No need to clear downstreamPending later 10712854Sgabeblack@google.com markPending = false; 10812854Sgabeblack@google.com } 10912854Sgabeblack@google.com } 11012854Sgabeblack@google.com 11112854Sgabeblack@google.com emplace_back(pkt, readyTime, order, source, markPending); 11212854Sgabeblack@google.com} 11312854Sgabeblack@google.com 11412854Sgabeblack@google.com 11512854Sgabeblack@google.comstatic void 11612854Sgabeblack@google.comreplaceUpgrade(PacketPtr pkt) 11712854Sgabeblack@google.com{ 11812854Sgabeblack@google.com // remember if the current packet has data allocated 11912854Sgabeblack@google.com bool has_data = pkt->hasData() || pkt->hasRespData(); 12012854Sgabeblack@google.com 12112854Sgabeblack@google.com if (pkt->cmd == MemCmd::UpgradeReq) { 12212854Sgabeblack@google.com pkt->cmd = MemCmd::ReadExReq; 12312854Sgabeblack@google.com DPRINTF(Cache, "Replacing UpgradeReq with ReadExReq\n"); 12412854Sgabeblack@google.com } else if (pkt->cmd == MemCmd::SCUpgradeReq) { 12512854Sgabeblack@google.com pkt->cmd = MemCmd::SCUpgradeFailReq; 12612854Sgabeblack@google.com DPRINTF(Cache, "Replacing SCUpgradeReq with SCUpgradeFailReq\n"); 12712854Sgabeblack@google.com } else if (pkt->cmd == MemCmd::StoreCondReq) { 12812854Sgabeblack@google.com pkt->cmd = MemCmd::StoreCondFailReq; 12912854Sgabeblack@google.com DPRINTF(Cache, "Replacing StoreCondReq with StoreCondFailReq\n"); 13012854Sgabeblack@google.com } 13112854Sgabeblack@google.com 13212854Sgabeblack@google.com if (!has_data) { 13312854Sgabeblack@google.com // there is no sensible way of setting the data field if the 13412854Sgabeblack@google.com // new command actually would carry data 13512854Sgabeblack@google.com assert(!pkt->hasData()); 13612854Sgabeblack@google.com 13712854Sgabeblack@google.com if (pkt->hasRespData()) { 13812854Sgabeblack@google.com // we went from a packet that had no data (neither request, 13912854Sgabeblack@google.com // nor response), to one that does, and therefore we need to 14012854Sgabeblack@google.com // actually allocate space for the data payload 14112854Sgabeblack@google.com pkt->allocate(); 14212854Sgabeblack@google.com } 14312854Sgabeblack@google.com } 14412854Sgabeblack@google.com} 14512854Sgabeblack@google.com 14612854Sgabeblack@google.com 14712854Sgabeblack@google.comvoid 14812854Sgabeblack@google.comMSHR::TargetList::replaceUpgrades() 14912854Sgabeblack@google.com{ 15012854Sgabeblack@google.com if (!hasUpgrade) 15112854Sgabeblack@google.com return; 15212854Sgabeblack@google.com 15312854Sgabeblack@google.com for (auto& t : *this) { 15412854Sgabeblack@google.com replaceUpgrade(t.pkt); 15512854Sgabeblack@google.com } 15612854Sgabeblack@google.com 15712854Sgabeblack@google.com hasUpgrade = false; 15812854Sgabeblack@google.com} 15912854Sgabeblack@google.com 16012854Sgabeblack@google.com 16112854Sgabeblack@google.comvoid 16212854Sgabeblack@google.comMSHR::TargetList::clearDownstreamPending() 16312854Sgabeblack@google.com{ 16412854Sgabeblack@google.com for (auto& t : *this) { 16512854Sgabeblack@google.com if (t.markedPending) { 16612854Sgabeblack@google.com // Iterate over the SenderState stack and see if we find 16712854Sgabeblack@google.com // an MSHR entry. If we find one, clear the 16812854Sgabeblack@google.com // downstreamPending flag by calling 16912854Sgabeblack@google.com // clearDownstreamPending(). This recursively clears the 17012854Sgabeblack@google.com // downstreamPending flag in all caches this packet has 17112854Sgabeblack@google.com // passed through. 17212854Sgabeblack@google.com MSHR *mshr = t.pkt->findNextSenderState<MSHR>(); 17312854Sgabeblack@google.com if (mshr != NULL) { 17412854Sgabeblack@google.com mshr->clearDownstreamPending(); 17512854Sgabeblack@google.com } 17612854Sgabeblack@google.com } 17712854Sgabeblack@google.com } 17812854Sgabeblack@google.com} 17912854Sgabeblack@google.com 18012854Sgabeblack@google.com 18112854Sgabeblack@google.combool 18212854Sgabeblack@google.comMSHR::TargetList::checkFunctional(PacketPtr pkt) 18312854Sgabeblack@google.com{ 18412854Sgabeblack@google.com for (auto& t : *this) { 18512854Sgabeblack@google.com if (pkt->checkFunctional(t.pkt)) { 18612854Sgabeblack@google.com return true; 18712854Sgabeblack@google.com } 18812854Sgabeblack@google.com } 18912854Sgabeblack@google.com 19012854Sgabeblack@google.com return false; 19112854Sgabeblack@google.com} 19212854Sgabeblack@google.com 19312854Sgabeblack@google.com 19412854Sgabeblack@google.comvoid 19512854Sgabeblack@google.comMSHR::TargetList::print(std::ostream &os, int verbosity, 19612854Sgabeblack@google.com const std::string &prefix) const 19712854Sgabeblack@google.com{ 19812854Sgabeblack@google.com for (auto& t : *this) { 19912854Sgabeblack@google.com const char *s; 20012854Sgabeblack@google.com switch (t.source) { 20112854Sgabeblack@google.com case Target::FromCPU: 20212854Sgabeblack@google.com s = "FromCPU"; 20312854Sgabeblack@google.com break; 20412854Sgabeblack@google.com case Target::FromSnoop: 20512854Sgabeblack@google.com s = "FromSnoop"; 20612854Sgabeblack@google.com break; 20712854Sgabeblack@google.com case Target::FromPrefetcher: 20812854Sgabeblack@google.com s = "FromPrefetcher"; 20912854Sgabeblack@google.com break; 21012854Sgabeblack@google.com default: 21112854Sgabeblack@google.com s = ""; 21212854Sgabeblack@google.com break; 21312854Sgabeblack@google.com } 21412854Sgabeblack@google.com ccprintf(os, "%s%s: ", prefix, s); 21512854Sgabeblack@google.com t.pkt->print(os, verbosity, ""); 21612854Sgabeblack@google.com } 21712854Sgabeblack@google.com} 21812854Sgabeblack@google.com 21912854Sgabeblack@google.com 22012854Sgabeblack@google.comvoid 22112854Sgabeblack@google.comMSHR::allocate(Addr blk_addr, unsigned blk_size, PacketPtr target, 22212854Sgabeblack@google.com Tick when_ready, Counter _order, bool alloc_on_fill) 22312854Sgabeblack@google.com{ 22412854Sgabeblack@google.com blkAddr = blk_addr; 22512854Sgabeblack@google.com blkSize = blk_size; 22612854Sgabeblack@google.com isSecure = target->isSecure(); 22712854Sgabeblack@google.com readyTime = when_ready; 22812854Sgabeblack@google.com order = _order; 22912854Sgabeblack@google.com assert(target); 23012854Sgabeblack@google.com isForward = false; 23112854Sgabeblack@google.com allocOnFill = alloc_on_fill; 23212854Sgabeblack@google.com _isUncacheable = target->req->isUncacheable(); 23312854Sgabeblack@google.com inService = false; 23412854Sgabeblack@google.com downstreamPending = false; 23512854Sgabeblack@google.com assert(targets.isReset()); 23612854Sgabeblack@google.com // Don't know of a case where we would allocate a new MSHR for a 23712854Sgabeblack@google.com // snoop (mem-side request), so set source according to request here 23812854Sgabeblack@google.com Target::Source source = (target->cmd == MemCmd::HardPFReq) ? 23912854Sgabeblack@google.com Target::FromPrefetcher : Target::FromCPU; 24012854Sgabeblack@google.com targets.add(target, when_ready, _order, source, true); 24112854Sgabeblack@google.com assert(deferredTargets.isReset()); 24212854Sgabeblack@google.com data = NULL; 24312854Sgabeblack@google.com} 24412854Sgabeblack@google.com 24512854Sgabeblack@google.com 24612854Sgabeblack@google.comvoid 24712854Sgabeblack@google.comMSHR::clearDownstreamPending() 24812854Sgabeblack@google.com{ 24912854Sgabeblack@google.com assert(downstreamPending); 25012854Sgabeblack@google.com downstreamPending = false; 25112854Sgabeblack@google.com // recursively clear flag on any MSHRs we will be forwarding 25212854Sgabeblack@google.com // responses to 25312854Sgabeblack@google.com targets.clearDownstreamPending(); 25412854Sgabeblack@google.com} 25512854Sgabeblack@google.com 25612854Sgabeblack@google.combool 25712854Sgabeblack@google.comMSHR::markInService(bool pending_modified_resp) 25812854Sgabeblack@google.com{ 25912854Sgabeblack@google.com assert(!inService); 26012854Sgabeblack@google.com if (isForwardNoResponse()) { 26112854Sgabeblack@google.com // we just forwarded the request packet & don't expect a 26212854Sgabeblack@google.com // response, so get rid of it 26312854Sgabeblack@google.com assert(getNumTargets() == 1); 26412854Sgabeblack@google.com popTarget(); 26512854Sgabeblack@google.com return true; 26612854Sgabeblack@google.com } 26712854Sgabeblack@google.com 26812854Sgabeblack@google.com inService = true; 26912854Sgabeblack@google.com pendingModified = targets.needsWritable || pending_modified_resp; 27012854Sgabeblack@google.com postInvalidate = postDowngrade = false; 27112854Sgabeblack@google.com 27212854Sgabeblack@google.com if (!downstreamPending) { 27312854Sgabeblack@google.com // let upstream caches know that the request has made it to a 27412854Sgabeblack@google.com // level where it's going to get a response 27512854Sgabeblack@google.com targets.clearDownstreamPending(); 27612854Sgabeblack@google.com } 27712854Sgabeblack@google.com return false; 27812854Sgabeblack@google.com} 27912854Sgabeblack@google.com 28012854Sgabeblack@google.com 28112854Sgabeblack@google.comvoid 28212854Sgabeblack@google.comMSHR::deallocate() 28312854Sgabeblack@google.com{ 28412854Sgabeblack@google.com assert(targets.empty()); 28512854Sgabeblack@google.com targets.resetFlags(); 28612854Sgabeblack@google.com assert(deferredTargets.isReset()); 28712854Sgabeblack@google.com inService = false; 28812854Sgabeblack@google.com} 28912854Sgabeblack@google.com 29012854Sgabeblack@google.com/* 29112854Sgabeblack@google.com * Adds a target to an MSHR 29212854Sgabeblack@google.com */ 29312854Sgabeblack@google.comvoid 29412854Sgabeblack@google.comMSHR::allocateTarget(PacketPtr pkt, Tick whenReady, Counter _order, 29512854Sgabeblack@google.com bool alloc_on_fill) 29612854Sgabeblack@google.com{ 29712854Sgabeblack@google.com // assume we'd never issue a prefetch when we've got an 29812854Sgabeblack@google.com // outstanding miss 29912854Sgabeblack@google.com assert(pkt->cmd != MemCmd::HardPFReq); 30012854Sgabeblack@google.com 30112854Sgabeblack@google.com // uncacheable accesses always allocate a new MSHR, and cacheable 30212854Sgabeblack@google.com // accesses ignore any uncacheable MSHRs, thus we should never 30312854Sgabeblack@google.com // have targets addded if originally allocated uncacheable 30412854Sgabeblack@google.com assert(!_isUncacheable); 30512854Sgabeblack@google.com 30612854Sgabeblack@google.com // potentially re-evaluate whether we should allocate on a fill or 30712854Sgabeblack@google.com // not 30812854Sgabeblack@google.com allocOnFill = allocOnFill || alloc_on_fill; 30912854Sgabeblack@google.com 31012854Sgabeblack@google.com // if there's a request already in service for this MSHR, we will 31112854Sgabeblack@google.com // have to defer the new target until after the response if any of 31212854Sgabeblack@google.com // the following are true: 31312854Sgabeblack@google.com // - there are other targets already deferred 31412854Sgabeblack@google.com // - there's a pending invalidate to be applied after the response 31512854Sgabeblack@google.com // comes back (but before this target is processed) 31612854Sgabeblack@google.com // - this target requires a writable block and either we're not 31712854Sgabeblack@google.com // getting a writable block back or we have already snooped 31812854Sgabeblack@google.com // another read request that will downgrade our writable block 31912854Sgabeblack@google.com // to non-writable (Shared or Owned) 32012854Sgabeblack@google.com if (inService && 32112854Sgabeblack@google.com (!deferredTargets.empty() || hasPostInvalidate() || 32212854Sgabeblack@google.com (pkt->needsWritable() && 32312854Sgabeblack@google.com (!isPendingModified() || hasPostDowngrade() || isForward)))) { 32412854Sgabeblack@google.com // need to put on deferred list 32512854Sgabeblack@google.com if (hasPostInvalidate()) 32612854Sgabeblack@google.com replaceUpgrade(pkt); 32712854Sgabeblack@google.com deferredTargets.add(pkt, whenReady, _order, Target::FromCPU, true); 32812854Sgabeblack@google.com } else { 32912854Sgabeblack@google.com // No request outstanding, or still OK to append to 33012854Sgabeblack@google.com // outstanding request: append to regular target list. Only 33112854Sgabeblack@google.com // mark pending if current request hasn't been issued yet 33212854Sgabeblack@google.com // (isn't in service). 33312854Sgabeblack@google.com targets.add(pkt, whenReady, _order, Target::FromCPU, !inService); 33412854Sgabeblack@google.com } 33512854Sgabeblack@google.com} 33612854Sgabeblack@google.com 33712854Sgabeblack@google.combool 33812854Sgabeblack@google.comMSHR::handleSnoop(PacketPtr pkt, Counter _order) 33912854Sgabeblack@google.com{ 34012854Sgabeblack@google.com DPRINTF(Cache, "%s for %s addr %#llx size %d\n", __func__, 34112854Sgabeblack@google.com pkt->cmdString(), pkt->getAddr(), pkt->getSize()); 34212854Sgabeblack@google.com 34312854Sgabeblack@google.com // when we snoop packets the needsWritable and isInvalidate flags 34412854Sgabeblack@google.com // should always be the same, however, this assumes that we never 34512854Sgabeblack@google.com // snoop writes as they are currently not marked as invalidations 34612854Sgabeblack@google.com panic_if(pkt->needsWritable() != pkt->isInvalidate(), 34712854Sgabeblack@google.com "%s got snoop %s to addr %#llx where needsWritable, " 34812854Sgabeblack@google.com "does not match isInvalidate", name(), pkt->cmdString(), 34912854Sgabeblack@google.com pkt->getAddr()); 35012854Sgabeblack@google.com 35112854Sgabeblack@google.com if (!inService || (pkt->isExpressSnoop() && downstreamPending)) { 35212854Sgabeblack@google.com // Request has not been issued yet, or it's been issued 35312854Sgabeblack@google.com // locally but is buffered unissued at some downstream cache 35412854Sgabeblack@google.com // which is forwarding us this snoop. Either way, the packet 35512854Sgabeblack@google.com // we're snooping logically precedes this MSHR's request, so 35612854Sgabeblack@google.com // the snoop has no impact on the MSHR, but must be processed 35712854Sgabeblack@google.com // in the standard way by the cache. The only exception is 35812854Sgabeblack@google.com // that if we're an L2+ cache buffering an UpgradeReq from a 35912854Sgabeblack@google.com // higher-level cache, and the snoop is invalidating, then our 36012854Sgabeblack@google.com // buffered upgrades must be converted to read exclusives, 36112854Sgabeblack@google.com // since the upper-level cache no longer has a valid copy. 36212854Sgabeblack@google.com // That is, even though the upper-level cache got out on its 36312854Sgabeblack@google.com // local bus first, some other invalidating transaction 36412854Sgabeblack@google.com // reached the global bus before the upgrade did. 36512854Sgabeblack@google.com if (pkt->needsWritable()) { 36612854Sgabeblack@google.com targets.replaceUpgrades(); 36712854Sgabeblack@google.com deferredTargets.replaceUpgrades(); 36812854Sgabeblack@google.com } 36912854Sgabeblack@google.com 37012854Sgabeblack@google.com return false; 37112854Sgabeblack@google.com } 37212854Sgabeblack@google.com 37312854Sgabeblack@google.com // From here on down, the request issued by this MSHR logically 37412854Sgabeblack@google.com // precedes the request we're snooping. 37512854Sgabeblack@google.com if (pkt->needsWritable()) { 37612854Sgabeblack@google.com // snooped request still precedes the re-request we'll have to 37712854Sgabeblack@google.com // issue for deferred targets, if any... 37812854Sgabeblack@google.com deferredTargets.replaceUpgrades(); 37912854Sgabeblack@google.com } 38012854Sgabeblack@google.com 38112854Sgabeblack@google.com if (hasPostInvalidate()) { 38212854Sgabeblack@google.com // a prior snoop has already appended an invalidation, so 38312854Sgabeblack@google.com // logically we don't have the block anymore; no need for 38412854Sgabeblack@google.com // further snooping. 38512854Sgabeblack@google.com return true; 38612854Sgabeblack@google.com } 38713322Sgabeblack@google.com 38813322Sgabeblack@google.com if (isPendingModified() || pkt->isInvalidate()) { 38912854Sgabeblack@google.com // We need to save and replay the packet in two cases: 39012854Sgabeblack@google.com // 1. We're awaiting a writable copy (Modified or Exclusive), 39112854Sgabeblack@google.com // so this MSHR is the orgering point, and we need to respond 39212854Sgabeblack@google.com // after we receive data. 39312854Sgabeblack@google.com // 2. It's an invalidation (e.g., UpgradeReq), and we need 39412854Sgabeblack@google.com // to forward the snoop up the hierarchy after the current 39512854Sgabeblack@google.com // transaction completes. 39612854Sgabeblack@google.com 39712854Sgabeblack@google.com // Start by determining if we will eventually respond or not, 39812854Sgabeblack@google.com // matching the conditions checked in Cache::handleSnoop 39912854Sgabeblack@google.com bool will_respond = isPendingModified() && pkt->needsResponse() && 40012854Sgabeblack@google.com pkt->cmd != MemCmd::InvalidateReq; 40112854Sgabeblack@google.com 40212854Sgabeblack@google.com // The packet we are snooping may be deleted by the time we 40312854Sgabeblack@google.com // actually process the target, and we consequently need to 40412854Sgabeblack@google.com // save a copy here. Clear flags and also allocate new data as 40512854Sgabeblack@google.com // the original packet data storage may have been deleted by 40612854Sgabeblack@google.com // the time we get to process this packet. In the cases where 40712854Sgabeblack@google.com // we are not responding after handling the snoop we also need 40812854Sgabeblack@google.com // to create a copy of the request to be on the safe side. In 40912854Sgabeblack@google.com // the latter case the cache is responsible for deleting both 41012854Sgabeblack@google.com // the packet and the request as part of handling the deferred 41112854Sgabeblack@google.com // snoop. 41212854Sgabeblack@google.com PacketPtr cp_pkt = will_respond ? new Packet(pkt, true, true) : 41312854Sgabeblack@google.com new Packet(new Request(*pkt->req), pkt->cmd); 41412854Sgabeblack@google.com 41512854Sgabeblack@google.com if (isPendingModified()) { 41612854Sgabeblack@google.com // we are the ordering point, and will consequently 41712854Sgabeblack@google.com // respond, and depending on whether the packet 41812854Sgabeblack@google.com // needsWritable or not we either pass a Shared line or a 41912854Sgabeblack@google.com // Modified line 42012854Sgabeblack@google.com pkt->setCacheResponding(); 42112854Sgabeblack@google.com 42212854Sgabeblack@google.com // inform the cache hierarchy that this cache had the line 42312854Sgabeblack@google.com // in the Modified state, even if the response is passed 42412854Sgabeblack@google.com // as Shared (and thus non-writable) 42512854Sgabeblack@google.com pkt->setResponderHadWritable(); 42612854Sgabeblack@google.com 42712854Sgabeblack@google.com // in the case of an uncacheable request there is no need 42812854Sgabeblack@google.com // to set the responderHadWritable flag, but since the 42912854Sgabeblack@google.com // recipient does not care there is no harm in doing so 43012854Sgabeblack@google.com } 43112854Sgabeblack@google.com targets.add(cp_pkt, curTick(), _order, Target::FromSnoop, 43212854Sgabeblack@google.com downstreamPending && targets.needsWritable); 43312854Sgabeblack@google.com 43412854Sgabeblack@google.com if (pkt->needsWritable()) { 43512854Sgabeblack@google.com // This transaction will take away our pending copy 43612854Sgabeblack@google.com postInvalidate = true; 43712854Sgabeblack@google.com } 43812854Sgabeblack@google.com } 43912854Sgabeblack@google.com 44012854Sgabeblack@google.com if (!pkt->needsWritable() && !pkt->req->isUncacheable()) { 44112854Sgabeblack@google.com // This transaction will get a read-shared copy, downgrading 44212854Sgabeblack@google.com // our copy if we had a writable one 44312854Sgabeblack@google.com postDowngrade = true; 44412854Sgabeblack@google.com // make sure that any downstream cache does not respond with a 44512854Sgabeblack@google.com // writable (and dirty) copy even if it has one, unless it was 44612854Sgabeblack@google.com // explicitly asked for one 44712854Sgabeblack@google.com pkt->setHasSharers(); 44812854Sgabeblack@google.com } 44912854Sgabeblack@google.com 45012854Sgabeblack@google.com return true; 45112854Sgabeblack@google.com} 45212854Sgabeblack@google.com 45312854Sgabeblack@google.com 45412854Sgabeblack@google.combool 45512854Sgabeblack@google.comMSHR::promoteDeferredTargets() 45612854Sgabeblack@google.com{ 45712854Sgabeblack@google.com assert(targets.empty()); 45812854Sgabeblack@google.com if (deferredTargets.empty()) { 45912854Sgabeblack@google.com return false; 46012854Sgabeblack@google.com } 46112854Sgabeblack@google.com 46212854Sgabeblack@google.com // swap targets & deferredTargets lists 46312854Sgabeblack@google.com std::swap(targets, deferredTargets); 46412854Sgabeblack@google.com 46512854Sgabeblack@google.com // clear deferredTargets flags 46612854Sgabeblack@google.com deferredTargets.resetFlags(); 46712854Sgabeblack@google.com 46812854Sgabeblack@google.com order = targets.front().order; 46912854Sgabeblack@google.com readyTime = std::max(curTick(), targets.front().readyTime); 47012854Sgabeblack@google.com 47112854Sgabeblack@google.com return true; 47212854Sgabeblack@google.com} 47312854Sgabeblack@google.com 47412854Sgabeblack@google.com 47512854Sgabeblack@google.comvoid 47612854Sgabeblack@google.comMSHR::promoteWritable() 47712854Sgabeblack@google.com{ 47812854Sgabeblack@google.com if (deferredTargets.needsWritable && 47912854Sgabeblack@google.com !(hasPostInvalidate() || hasPostDowngrade())) { 48012854Sgabeblack@google.com // We got a writable response, but we have deferred targets 48112854Sgabeblack@google.com // which are waiting to request a writable copy (not because 48212854Sgabeblack@google.com // of a pending invalidate). This can happen if the original 48312854Sgabeblack@google.com // request was for a read-only block, but we got a writable 48412854Sgabeblack@google.com // response anyway. Since we got the writable copy there's no 48512854Sgabeblack@google.com // need to defer the targets, so move them up to the regular 48612854Sgabeblack@google.com // target list. 48712854Sgabeblack@google.com assert(!targets.needsWritable); 48812854Sgabeblack@google.com targets.needsWritable = true; 48912854Sgabeblack@google.com // if any of the deferred targets were upper-level cache 49012854Sgabeblack@google.com // requests marked downstreamPending, need to clear that 49112854Sgabeblack@google.com assert(!downstreamPending); // not pending here anymore 49212854Sgabeblack@google.com deferredTargets.clearDownstreamPending(); 49312854Sgabeblack@google.com // this clears out deferredTargets too 49412854Sgabeblack@google.com targets.splice(targets.end(), deferredTargets); 49512854Sgabeblack@google.com deferredTargets.resetFlags(); 49612854Sgabeblack@google.com } 49712854Sgabeblack@google.com} 49812854Sgabeblack@google.com 49912854Sgabeblack@google.com 50012854Sgabeblack@google.combool 50112854Sgabeblack@google.comMSHR::checkFunctional(PacketPtr pkt) 50212854Sgabeblack@google.com{ 50312854Sgabeblack@google.com // For printing, we treat the MSHR as a whole as single entity. 50412854Sgabeblack@google.com // For other requests, we iterate over the individual targets 50512854Sgabeblack@google.com // since that's where the actual data lies. 50612854Sgabeblack@google.com if (pkt->isPrint()) { 50712854Sgabeblack@google.com pkt->checkFunctional(this, blkAddr, isSecure, blkSize, NULL); 50812854Sgabeblack@google.com return false; 50912854Sgabeblack@google.com } else { 51012854Sgabeblack@google.com return (targets.checkFunctional(pkt) || 51112854Sgabeblack@google.com deferredTargets.checkFunctional(pkt)); 51212854Sgabeblack@google.com } 51312854Sgabeblack@google.com} 51412854Sgabeblack@google.com 51512854Sgabeblack@google.com 51612854Sgabeblack@google.comvoid 51712854Sgabeblack@google.comMSHR::print(std::ostream &os, int verbosity, const std::string &prefix) const 51812854Sgabeblack@google.com{ 51912854Sgabeblack@google.com ccprintf(os, "%s[%#llx:%#llx](%s) %s %s %s state: %s %s %s %s %s\n", 52012854Sgabeblack@google.com prefix, blkAddr, blkAddr + blkSize - 1, 52112854Sgabeblack@google.com isSecure ? "s" : "ns", 52212854Sgabeblack@google.com isForward ? "Forward" : "", 52312854Sgabeblack@google.com allocOnFill ? "AllocOnFill" : "", 52412854Sgabeblack@google.com isForwardNoResponse() ? "ForwNoResp" : "", 52512854Sgabeblack@google.com needsWritable() ? "Wrtbl" : "", 52612854Sgabeblack@google.com _isUncacheable ? "Unc" : "", 52712854Sgabeblack@google.com inService ? "InSvc" : "", 52812854Sgabeblack@google.com downstreamPending ? "DwnPend" : "", 52912854Sgabeblack@google.com hasPostInvalidate() ? "PostInv" : "", 53012854Sgabeblack@google.com hasPostDowngrade() ? "PostDowngr" : ""); 53112854Sgabeblack@google.com 53212854Sgabeblack@google.com ccprintf(os, "%s Targets:\n", prefix); 53312854Sgabeblack@google.com targets.print(os, verbosity, prefix + " "); 53412854Sgabeblack@google.com if (!deferredTargets.empty()) { 53512854Sgabeblack@google.com ccprintf(os, "%s Deferred Targets:\n", prefix); 53612854Sgabeblack@google.com deferredTargets.print(os, verbosity, prefix + " "); 53712854Sgabeblack@google.com } 53812854Sgabeblack@google.com} 53912854Sgabeblack@google.com 54012854Sgabeblack@google.comstd::string 54112854Sgabeblack@google.comMSHR::print() const 54212854Sgabeblack@google.com{ 54312854Sgabeblack@google.com ostringstream str; 54412854Sgabeblack@google.com print(str); 54512854Sgabeblack@google.com return str.str(); 54612854Sgabeblack@google.com} 54712854Sgabeblack@google.com