mshr.cc revision 12637
12381SN/A/* 28853Sandreas.hansson@arm.com * Copyright (c) 2012-2013, 2015-2018 ARM Limited 38711Sandreas.hansson@arm.com * All rights reserved. 48711Sandreas.hansson@arm.com * 58711Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall 68711Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual 78711Sandreas.hansson@arm.com * property including but not limited to intellectual property relating 88711Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software 98711Sandreas.hansson@arm.com * licensed hereunder. You may use the software subject to the license 108711Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated 118711Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software, 128711Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form. 138711Sandreas.hansson@arm.com * 142381SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 152381SN/A * Copyright (c) 2010 Advanced Micro Devices, Inc. 162381SN/A * All rights reserved. 172381SN/A * 182381SN/A * Redistribution and use in source and binary forms, with or without 192381SN/A * modification, are permitted provided that the following conditions are 202381SN/A * met: redistributions of source code must retain the above copyright 212381SN/A * notice, this list of conditions and the following disclaimer; 222381SN/A * redistributions in binary form must reproduce the above copyright 232381SN/A * notice, this list of conditions and the following disclaimer in the 242381SN/A * documentation and/or other materials provided with the distribution; 252381SN/A * neither the name of the copyright holders nor the names of its 262381SN/A * contributors may be used to endorse or promote products derived from 272381SN/A * this software without specific prior written permission. 282381SN/A * 292381SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 302381SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 312381SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 322381SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 332381SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 342381SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 352381SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 362381SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 372381SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 382381SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 392665Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 402665Ssaidi@eecs.umich.edu * 418853Sandreas.hansson@arm.com * Authors: Erik Hallnor 428922Swilliam.wang@arm.com * Dave Greene 432381SN/A */ 442381SN/A 452381SN/A/** 462381SN/A * @file 478922Swilliam.wang@arm.com * Miss Status and Handling Register (MSHR) definitions. 482381SN/A */ 492381SN/A 502381SN/A#include "mem/cache/mshr.hh" 512381SN/A 522381SN/A#include <algorithm> 532381SN/A#include <cassert> 542381SN/A#include <string> 552381SN/A#include <vector> 562381SN/A 572381SN/A#include "base/logging.hh" 588922Swilliam.wang@arm.com#include "base/types.hh" 598922Swilliam.wang@arm.com#include "debug/Cache.hh" 602407SN/A#include "mem/cache/cache.hh" 612407SN/A#include "sim/core.hh" 622407SN/A 632407SN/AMSHR::MSHR() : downstreamPending(false), 642407SN/A pendingModified(false), 652407SN/A postInvalidate(false), postDowngrade(false), 662521SN/A isForward(false) 672407SN/A{ 683401Sktlim@umich.edu} 693401Sktlim@umich.edu 702381SN/AMSHR::TargetList::TargetList() 718922Swilliam.wang@arm.com : needsWritable(false), hasUpgrade(false), allocOnFill(false) 728922Swilliam.wang@arm.com{} 739087Sandreas.hansson@arm.com 742381SN/A 758708Sandreas.hansson@arm.comvoid 762381SN/AMSHR::TargetList::updateFlags(PacketPtr pkt, Target::Source source, 778922Swilliam.wang@arm.com bool alloc_on_fill) 788922Swilliam.wang@arm.com{ 798922Swilliam.wang@arm.com if (source != Target::FromSnoop) { 808922Swilliam.wang@arm.com if (pkt->needsWritable()) { 818922Swilliam.wang@arm.com needsWritable = true; 828922Swilliam.wang@arm.com } 835476Snate@binkert.org 842640Sstever@eecs.umich.edu // StoreCondReq is effectively an upgrade if it's in an MSHR 858965Sandreas.hansson@arm.com // since it would have been failed already if we didn't have a 868965Sandreas.hansson@arm.com // read-only copy 879031Sandreas.hansson@arm.com if (pkt->isUpgrade() || pkt->cmd == MemCmd::StoreCondReq) { 888965Sandreas.hansson@arm.com hasUpgrade = true; 899031Sandreas.hansson@arm.com } 908965Sandreas.hansson@arm.com 918922Swilliam.wang@arm.com // potentially re-evaluate whether we should allocate on a fill or 928922Swilliam.wang@arm.com // not 938922Swilliam.wang@arm.com allocOnFill = allocOnFill || alloc_on_fill; 948922Swilliam.wang@arm.com } 958922Swilliam.wang@arm.com} 968922Swilliam.wang@arm.com 978922Swilliam.wang@arm.comvoid 988922Swilliam.wang@arm.comMSHR::TargetList::populateFlags() 998965Sandreas.hansson@arm.com{ 1008922Swilliam.wang@arm.com resetFlags(); 1019031Sandreas.hansson@arm.com for (auto& t: *this) { 1028922Swilliam.wang@arm.com updateFlags(t.pkt, t.source, t.allocOnFill); 1038922Swilliam.wang@arm.com } 1048922Swilliam.wang@arm.com} 1058922Swilliam.wang@arm.com 1068922Swilliam.wang@arm.cominline void 1073401Sktlim@umich.eduMSHR::TargetList::add(PacketPtr pkt, Tick readyTime, 1082381SN/A Counter order, Target::Source source, bool markPending, 1092640Sstever@eecs.umich.edu bool alloc_on_fill) 1102640Sstever@eecs.umich.edu{ 1118922Swilliam.wang@arm.com updateFlags(pkt, source, alloc_on_fill); 1124190Ssaidi@eecs.umich.edu if (markPending) { 1138965Sandreas.hansson@arm.com // Iterate over the SenderState stack and see if we find 1149031Sandreas.hansson@arm.com // an MSHR entry. If we do, set the downstreamPending 1158965Sandreas.hansson@arm.com // flag. Otherwise, do nothing. 1168922Swilliam.wang@arm.com MSHR *mshr = pkt->findNextSenderState<MSHR>(); 1178922Swilliam.wang@arm.com if (mshr != nullptr) { 1188922Swilliam.wang@arm.com assert(!mshr->downstreamPending); 1198922Swilliam.wang@arm.com mshr->downstreamPending = true; 1208922Swilliam.wang@arm.com } else { 1218922Swilliam.wang@arm.com // No need to clear downstreamPending later 1228922Swilliam.wang@arm.com markPending = false; 1238922Swilliam.wang@arm.com } 1248922Swilliam.wang@arm.com } 1258922Swilliam.wang@arm.com 1268922Swilliam.wang@arm.com emplace_back(pkt, readyTime, order, source, markPending, alloc_on_fill); 1278922Swilliam.wang@arm.com} 1288922Swilliam.wang@arm.com 1298922Swilliam.wang@arm.com 1308975Sandreas.hansson@arm.comstatic void 1318975Sandreas.hansson@arm.comreplaceUpgrade(PacketPtr pkt) 1328922Swilliam.wang@arm.com{ 1338922Swilliam.wang@arm.com // remember if the current packet has data allocated 1348922Swilliam.wang@arm.com bool has_data = pkt->hasData() || pkt->hasRespData(); 1358922Swilliam.wang@arm.com 1368922Swilliam.wang@arm.com if (pkt->cmd == MemCmd::UpgradeReq) { 1378922Swilliam.wang@arm.com pkt->cmd = MemCmd::ReadExReq; 1388965Sandreas.hansson@arm.com DPRINTF(Cache, "Replacing UpgradeReq with ReadExReq\n"); 1399031Sandreas.hansson@arm.com } else if (pkt->cmd == MemCmd::SCUpgradeReq) { 1408922Swilliam.wang@arm.com pkt->cmd = MemCmd::SCUpgradeFailReq; 1418922Swilliam.wang@arm.com DPRINTF(Cache, "Replacing SCUpgradeReq with SCUpgradeFailReq\n"); 1428922Swilliam.wang@arm.com } else if (pkt->cmd == MemCmd::StoreCondReq) { 1438922Swilliam.wang@arm.com pkt->cmd = MemCmd::StoreCondFailReq; 1448922Swilliam.wang@arm.com DPRINTF(Cache, "Replacing StoreCondReq with StoreCondFailReq\n"); 1458922Swilliam.wang@arm.com } 1468922Swilliam.wang@arm.com 1478948Sandreas.hansson@arm.com if (!has_data) { 1488948Sandreas.hansson@arm.com // there is no sensible way of setting the data field if the 1498948Sandreas.hansson@arm.com // new command actually would carry data 1508948Sandreas.hansson@arm.com assert(!pkt->hasData()); 1518948Sandreas.hansson@arm.com 1528948Sandreas.hansson@arm.com if (pkt->hasRespData()) { 1538948Sandreas.hansson@arm.com // we went from a packet that had no data (neither request, 1548948Sandreas.hansson@arm.com // nor response), to one that does, and therefore we need to 1558948Sandreas.hansson@arm.com // actually allocate space for the data payload 1568948Sandreas.hansson@arm.com pkt->allocate(); 1578948Sandreas.hansson@arm.com } 1588948Sandreas.hansson@arm.com } 1598948Sandreas.hansson@arm.com} 1608948Sandreas.hansson@arm.com 1618948Sandreas.hansson@arm.com 1628948Sandreas.hansson@arm.comvoid 1638948Sandreas.hansson@arm.comMSHR::TargetList::replaceUpgrades() 1648948Sandreas.hansson@arm.com{ 1658948Sandreas.hansson@arm.com if (!hasUpgrade) 1668948Sandreas.hansson@arm.com return; 1678975Sandreas.hansson@arm.com 1688975Sandreas.hansson@arm.com for (auto& t : *this) { 1698975Sandreas.hansson@arm.com replaceUpgrade(t.pkt); 1708975Sandreas.hansson@arm.com } 1718975Sandreas.hansson@arm.com 1728975Sandreas.hansson@arm.com hasUpgrade = false; 1738975Sandreas.hansson@arm.com} 1748975Sandreas.hansson@arm.com 1758975Sandreas.hansson@arm.com 1768975Sandreas.hansson@arm.comvoid 1778975Sandreas.hansson@arm.comMSHR::TargetList::clearDownstreamPending() 1788948Sandreas.hansson@arm.com{ 1798948Sandreas.hansson@arm.com for (auto& t : *this) { 1808975Sandreas.hansson@arm.com if (t.markedPending) { 1818975Sandreas.hansson@arm.com // Iterate over the SenderState stack and see if we find 1828975Sandreas.hansson@arm.com // an MSHR entry. If we find one, clear the 1838975Sandreas.hansson@arm.com // downstreamPending flag by calling 1848975Sandreas.hansson@arm.com // clearDownstreamPending(). This recursively clears the 1858975Sandreas.hansson@arm.com // downstreamPending flag in all caches this packet has 1868975Sandreas.hansson@arm.com // passed through. 1878948Sandreas.hansson@arm.com MSHR *mshr = t.pkt->findNextSenderState<MSHR>(); 1888975Sandreas.hansson@arm.com if (mshr != nullptr) { 1898922Swilliam.wang@arm.com mshr->clearDownstreamPending(); 1908922Swilliam.wang@arm.com } 1919087Sandreas.hansson@arm.com t.markedPending = false; 1929087Sandreas.hansson@arm.com } 1939087Sandreas.hansson@arm.com } 1949087Sandreas.hansson@arm.com} 1959087Sandreas.hansson@arm.com 1969087Sandreas.hansson@arm.com 1978922Swilliam.wang@arm.combool 1988711Sandreas.hansson@arm.comMSHR::TargetList::checkFunctional(PacketPtr pkt) 1998922Swilliam.wang@arm.com{ 2008922Swilliam.wang@arm.com for (auto& t : *this) { 2018922Swilliam.wang@arm.com if (pkt->checkFunctional(t.pkt)) { 2028711Sandreas.hansson@arm.com return true; 2038711Sandreas.hansson@arm.com } 2048711Sandreas.hansson@arm.com } 2058922Swilliam.wang@arm.com 2062381SN/A return false; 2078711Sandreas.hansson@arm.com} 2088922Swilliam.wang@arm.com 2098922Swilliam.wang@arm.com 2108711Sandreas.hansson@arm.comvoid 2118922Swilliam.wang@arm.comMSHR::TargetList::print(std::ostream &os, int verbosity, 2122381SN/A const std::string &prefix) const 2132381SN/A{ 2142381SN/A for (auto& t : *this) { 2152381SN/A const char *s; 2168922Swilliam.wang@arm.com switch (t.source) { 2172381SN/A case Target::FromCPU: 2185314Sstever@gmail.com s = "FromCPU"; 2195314Sstever@gmail.com break; 2205314Sstever@gmail.com case Target::FromSnoop: 2215314Sstever@gmail.com s = "FromSnoop"; 2228975Sandreas.hansson@arm.com break; 2238975Sandreas.hansson@arm.com case Target::FromPrefetcher: 2248975Sandreas.hansson@arm.com s = "FromPrefetcher"; 2258975Sandreas.hansson@arm.com break; 2268975Sandreas.hansson@arm.com default: 2278975Sandreas.hansson@arm.com s = ""; 2288975Sandreas.hansson@arm.com break; 2298975Sandreas.hansson@arm.com } 2308975Sandreas.hansson@arm.com ccprintf(os, "%s%s: ", prefix, s); 2318975Sandreas.hansson@arm.com t.pkt->print(os, verbosity, ""); 2328975Sandreas.hansson@arm.com ccprintf(os, "\n"); 2338975Sandreas.hansson@arm.com } 2348975Sandreas.hansson@arm.com} 2358975Sandreas.hansson@arm.com 2368975Sandreas.hansson@arm.com 2378975Sandreas.hansson@arm.comvoid 2388975Sandreas.hansson@arm.comMSHR::allocate(Addr blk_addr, unsigned blk_size, PacketPtr target, 2398975Sandreas.hansson@arm.com Tick when_ready, Counter _order, bool alloc_on_fill) 2408975Sandreas.hansson@arm.com{ 2418975Sandreas.hansson@arm.com blkAddr = blk_addr; 2428975Sandreas.hansson@arm.com blkSize = blk_size; 2438975Sandreas.hansson@arm.com isSecure = target->isSecure(); 2448975Sandreas.hansson@arm.com readyTime = when_ready; 2458975Sandreas.hansson@arm.com order = _order; 2468975Sandreas.hansson@arm.com assert(target); 2478975Sandreas.hansson@arm.com isForward = false; 2488975Sandreas.hansson@arm.com _isUncacheable = target->req->isUncacheable(); 2498975Sandreas.hansson@arm.com inService = false; 2508975Sandreas.hansson@arm.com downstreamPending = false; 2518975Sandreas.hansson@arm.com assert(targets.isReset()); 2528975Sandreas.hansson@arm.com // Don't know of a case where we would allocate a new MSHR for a 2538975Sandreas.hansson@arm.com // snoop (mem-side request), so set source according to request here 2548975Sandreas.hansson@arm.com Target::Source source = (target->cmd == MemCmd::HardPFReq) ? 2558975Sandreas.hansson@arm.com Target::FromPrefetcher : Target::FromCPU; 2569087Sandreas.hansson@arm.com targets.add(target, when_ready, _order, source, true, alloc_on_fill); 2579087Sandreas.hansson@arm.com assert(deferredTargets.isReset()); 2589087Sandreas.hansson@arm.com} 2599087Sandreas.hansson@arm.com 2609087Sandreas.hansson@arm.com 2619087Sandreas.hansson@arm.comvoid 2629087Sandreas.hansson@arm.comMSHR::clearDownstreamPending() 2639087Sandreas.hansson@arm.com{ 2648975Sandreas.hansson@arm.com assert(downstreamPending); 2658975Sandreas.hansson@arm.com downstreamPending = false; 2668975Sandreas.hansson@arm.com // recursively clear flag on any MSHRs we will be forwarding 2678975Sandreas.hansson@arm.com // responses to 2688975Sandreas.hansson@arm.com targets.clearDownstreamPending(); 2698975Sandreas.hansson@arm.com} 2708975Sandreas.hansson@arm.com 2712381SN/Avoid 2722381SN/AMSHR::markInService(bool pending_modified_resp) 2738922Swilliam.wang@arm.com{ 2748922Swilliam.wang@arm.com assert(!inService); 2758922Swilliam.wang@arm.com 2768922Swilliam.wang@arm.com inService = true; 2778922Swilliam.wang@arm.com pendingModified = targets.needsWritable || pending_modified_resp; 2788922Swilliam.wang@arm.com postInvalidate = postDowngrade = false; 2798922Swilliam.wang@arm.com 2808922Swilliam.wang@arm.com if (!downstreamPending) { 2818922Swilliam.wang@arm.com // let upstream caches know that the request has made it to a 2828975Sandreas.hansson@arm.com // level where it's going to get a response 2838975Sandreas.hansson@arm.com targets.clearDownstreamPending(); 2848922Swilliam.wang@arm.com } 2858922Swilliam.wang@arm.com} 2868922Swilliam.wang@arm.com 2878922Swilliam.wang@arm.com 2888922Swilliam.wang@arm.comvoid 2898922Swilliam.wang@arm.comMSHR::deallocate() 2908965Sandreas.hansson@arm.com{ 2919031Sandreas.hansson@arm.com assert(targets.empty()); 2928922Swilliam.wang@arm.com targets.resetFlags(); 2938922Swilliam.wang@arm.com assert(deferredTargets.isReset()); 2948922Swilliam.wang@arm.com inService = false; 2958922Swilliam.wang@arm.com} 2968922Swilliam.wang@arm.com 2978922Swilliam.wang@arm.com/* 2988922Swilliam.wang@arm.com * Adds a target to an MSHR 2998948Sandreas.hansson@arm.com */ 3008948Sandreas.hansson@arm.comvoid 3018948Sandreas.hansson@arm.comMSHR::allocateTarget(PacketPtr pkt, Tick whenReady, Counter _order, 3028948Sandreas.hansson@arm.com bool alloc_on_fill) 3038948Sandreas.hansson@arm.com{ 3048948Sandreas.hansson@arm.com // assume we'd never issue a prefetch when we've got an 3058948Sandreas.hansson@arm.com // outstanding miss 3068948Sandreas.hansson@arm.com assert(pkt->cmd != MemCmd::HardPFReq); 3078948Sandreas.hansson@arm.com 3088948Sandreas.hansson@arm.com // uncacheable accesses always allocate a new MSHR, and cacheable 3098948Sandreas.hansson@arm.com // accesses ignore any uncacheable MSHRs, thus we should never 3108948Sandreas.hansson@arm.com // have targets addded if originally allocated uncacheable 3118948Sandreas.hansson@arm.com assert(!_isUncacheable); 3128948Sandreas.hansson@arm.com 3138948Sandreas.hansson@arm.com // if there's a request already in service for this MSHR, we will 3148948Sandreas.hansson@arm.com // have to defer the new target until after the response if any of 3158948Sandreas.hansson@arm.com // the following are true: 3168948Sandreas.hansson@arm.com // - there are other targets already deferred 3178948Sandreas.hansson@arm.com // - there's a pending invalidate to be applied after the response 3188948Sandreas.hansson@arm.com // comes back (but before this target is processed) 3198975Sandreas.hansson@arm.com // - the MSHR's first (and only) non-deferred target is a cache 3208975Sandreas.hansson@arm.com // maintenance packet 3218975Sandreas.hansson@arm.com // - the new target is a cache maintenance packet (this is probably 3228975Sandreas.hansson@arm.com // overly conservative but certainly safe) 3238975Sandreas.hansson@arm.com // - this target requires a writable block and either we're not 3248975Sandreas.hansson@arm.com // getting a writable block back or we have already snooped 3258975Sandreas.hansson@arm.com // another read request that will downgrade our writable block 3268975Sandreas.hansson@arm.com // to non-writable (Shared or Owned) 3278975Sandreas.hansson@arm.com PacketPtr tgt_pkt = targets.front().pkt; 3288975Sandreas.hansson@arm.com if (pkt->req->isCacheMaintenance() || 3298975Sandreas.hansson@arm.com tgt_pkt->req->isCacheMaintenance() || 3308948Sandreas.hansson@arm.com !deferredTargets.empty() || 3318948Sandreas.hansson@arm.com (inService && 3328975Sandreas.hansson@arm.com (hasPostInvalidate() || 3338975Sandreas.hansson@arm.com (pkt->needsWritable() && 3348975Sandreas.hansson@arm.com (!isPendingModified() || hasPostDowngrade() || isForward))))) { 3358975Sandreas.hansson@arm.com // need to put on deferred list 3368975Sandreas.hansson@arm.com if (inService && hasPostInvalidate()) 3378948Sandreas.hansson@arm.com replaceUpgrade(pkt); 3388975Sandreas.hansson@arm.com deferredTargets.add(pkt, whenReady, _order, Target::FromCPU, true, 3398948Sandreas.hansson@arm.com alloc_on_fill); 3408948Sandreas.hansson@arm.com } else { 3419087Sandreas.hansson@arm.com // No request outstanding, or still OK to append to 3429087Sandreas.hansson@arm.com // outstanding request: append to regular target list. Only 3439087Sandreas.hansson@arm.com // mark pending if current request hasn't been issued yet 3449087Sandreas.hansson@arm.com // (isn't in service). 3459087Sandreas.hansson@arm.com targets.add(pkt, whenReady, _order, Target::FromCPU, !inService, 3469087Sandreas.hansson@arm.com alloc_on_fill); 3479087Sandreas.hansson@arm.com } 3488922Swilliam.wang@arm.com} 3498922Swilliam.wang@arm.com 3508922Swilliam.wang@arm.combool 3518922Swilliam.wang@arm.comMSHR::handleSnoop(PacketPtr pkt, Counter _order) 3528922Swilliam.wang@arm.com{ 3538922Swilliam.wang@arm.com DPRINTF(Cache, "%s for %s\n", __func__, pkt->print()); 3548922Swilliam.wang@arm.com 3558922Swilliam.wang@arm.com // when we snoop packets the needsWritable and isInvalidate flags 3568922Swilliam.wang@arm.com // should always be the same, however, this assumes that we never 3578922Swilliam.wang@arm.com // snoop writes as they are currently not marked as invalidations 3588922Swilliam.wang@arm.com panic_if((pkt->needsWritable() != pkt->isInvalidate()) && 3598922Swilliam.wang@arm.com !pkt->req->isCacheMaintenance(), 3608922Swilliam.wang@arm.com "%s got snoop %s where needsWritable, " 3618922Swilliam.wang@arm.com "does not match isInvalidate", name(), pkt->print()); 3628922Swilliam.wang@arm.com 3638922Swilliam.wang@arm.com if (!inService || (pkt->isExpressSnoop() && downstreamPending)) { 3648922Swilliam.wang@arm.com // Request has not been issued yet, or it's been issued 3658922Swilliam.wang@arm.com // locally but is buffered unissued at some downstream cache 3668922Swilliam.wang@arm.com // which is forwarding us this snoop. Either way, the packet 3678922Swilliam.wang@arm.com // we're snooping logically precedes this MSHR's request, so 3688922Swilliam.wang@arm.com // the snoop has no impact on the MSHR, but must be processed 3698922Swilliam.wang@arm.com // in the standard way by the cache. The only exception is 3708922Swilliam.wang@arm.com // that if we're an L2+ cache buffering an UpgradeReq from a 3718975Sandreas.hansson@arm.com // higher-level cache, and the snoop is invalidating, then our 3728975Sandreas.hansson@arm.com // buffered upgrades must be converted to read exclusives, 3738975Sandreas.hansson@arm.com // since the upper-level cache no longer has a valid copy. 3748975Sandreas.hansson@arm.com // That is, even though the upper-level cache got out on its 3758975Sandreas.hansson@arm.com // local bus first, some other invalidating transaction 3768975Sandreas.hansson@arm.com // reached the global bus before the upgrade did. 3778975Sandreas.hansson@arm.com if (pkt->needsWritable() || pkt->req->isCacheInvalidate()) { 3788975Sandreas.hansson@arm.com targets.replaceUpgrades(); 3798975Sandreas.hansson@arm.com deferredTargets.replaceUpgrades(); 3808975Sandreas.hansson@arm.com } 3818975Sandreas.hansson@arm.com 3828975Sandreas.hansson@arm.com return false; 3838975Sandreas.hansson@arm.com } 3848975Sandreas.hansson@arm.com 3858975Sandreas.hansson@arm.com // From here on down, the request issued by this MSHR logically 3868975Sandreas.hansson@arm.com // precedes the request we're snooping. 3878975Sandreas.hansson@arm.com if (pkt->needsWritable() || pkt->req->isCacheInvalidate()) { 3888975Sandreas.hansson@arm.com // snooped request still precedes the re-request we'll have to 3898975Sandreas.hansson@arm.com // issue for deferred targets, if any... 3908975Sandreas.hansson@arm.com deferredTargets.replaceUpgrades(); 3918975Sandreas.hansson@arm.com } 3928975Sandreas.hansson@arm.com 3938975Sandreas.hansson@arm.com PacketPtr tgt_pkt = targets.front().pkt; 3948975Sandreas.hansson@arm.com if (hasPostInvalidate() || tgt_pkt->req->isCacheInvalidate()) { 3958975Sandreas.hansson@arm.com // a prior snoop has already appended an invalidation or a 3968975Sandreas.hansson@arm.com // cache invalidation operation is in progress, so logically 3979087Sandreas.hansson@arm.com // we don't have the block anymore; no need for further 3989087Sandreas.hansson@arm.com // snooping. 3999087Sandreas.hansson@arm.com return true; 4009087Sandreas.hansson@arm.com } 4019087Sandreas.hansson@arm.com 4029087Sandreas.hansson@arm.com if (isPendingModified() || pkt->isInvalidate()) { 4039087Sandreas.hansson@arm.com // We need to save and replay the packet in two cases: 4048922Swilliam.wang@arm.com // 1. We're awaiting a writable copy (Modified or Exclusive), 4058922Swilliam.wang@arm.com // so this MSHR is the orgering point, and we need to respond 4062381SN/A // after we receive data. 407 // 2. It's an invalidation (e.g., UpgradeReq), and we need 408 // to forward the snoop up the hierarchy after the current 409 // transaction completes. 410 411 // Start by determining if we will eventually respond or not, 412 // matching the conditions checked in Cache::handleSnoop 413 bool will_respond = isPendingModified() && pkt->needsResponse() && 414 !pkt->isClean(); 415 416 // The packet we are snooping may be deleted by the time we 417 // actually process the target, and we consequently need to 418 // save a copy here. Clear flags and also allocate new data as 419 // the original packet data storage may have been deleted by 420 // the time we get to process this packet. In the cases where 421 // we are not responding after handling the snoop we also need 422 // to create a copy of the request to be on the safe side. In 423 // the latter case the cache is responsible for deleting both 424 // the packet and the request as part of handling the deferred 425 // snoop. 426 PacketPtr cp_pkt = will_respond ? new Packet(pkt, true, true) : 427 new Packet(new Request(*pkt->req), pkt->cmd, blkSize, pkt->id); 428 429 if (will_respond) { 430 // we are the ordering point, and will consequently 431 // respond, and depending on whether the packet 432 // needsWritable or not we either pass a Shared line or a 433 // Modified line 434 pkt->setCacheResponding(); 435 436 // inform the cache hierarchy that this cache had the line 437 // in the Modified state, even if the response is passed 438 // as Shared (and thus non-writable) 439 pkt->setResponderHadWritable(); 440 441 // in the case of an uncacheable request there is no need 442 // to set the responderHadWritable flag, but since the 443 // recipient does not care there is no harm in doing so 444 } 445 targets.add(cp_pkt, curTick(), _order, Target::FromSnoop, 446 downstreamPending && targets.needsWritable, false); 447 448 if (pkt->needsWritable() || pkt->isInvalidate()) { 449 // This transaction will take away our pending copy 450 postInvalidate = true; 451 } 452 453 if (isPendingModified() && pkt->isClean()) { 454 pkt->setSatisfied(); 455 } 456 } 457 458 if (!pkt->needsWritable() && !pkt->req->isUncacheable()) { 459 // This transaction will get a read-shared copy, downgrading 460 // our copy if we had a writable one 461 postDowngrade = true; 462 // make sure that any downstream cache does not respond with a 463 // writable (and dirty) copy even if it has one, unless it was 464 // explicitly asked for one 465 pkt->setHasSharers(); 466 } 467 468 return true; 469} 470 471MSHR::TargetList 472MSHR::extractServiceableTargets(PacketPtr pkt) 473{ 474 TargetList ready_targets; 475 // If the downstream MSHR got an invalidation request then we only 476 // service the first of the FromCPU targets and any other 477 // non-FromCPU target. This way the remaining FromCPU targets 478 // issue a new request and get a fresh copy of the block and we 479 // avoid memory consistency violations. 480 if (pkt->cmd == MemCmd::ReadRespWithInvalidate) { 481 auto it = targets.begin(); 482 assert((it->source == Target::FromCPU) || 483 (it->source == Target::FromPrefetcher)); 484 ready_targets.push_back(*it); 485 it = targets.erase(it); 486 while (it != targets.end()) { 487 if (it->source == Target::FromCPU) { 488 it++; 489 } else { 490 assert(it->source == Target::FromSnoop); 491 ready_targets.push_back(*it); 492 it = targets.erase(it); 493 } 494 } 495 ready_targets.populateFlags(); 496 } else { 497 std::swap(ready_targets, targets); 498 } 499 targets.populateFlags(); 500 501 return ready_targets; 502} 503 504bool 505MSHR::promoteDeferredTargets() 506{ 507 if (targets.empty() && deferredTargets.empty()) { 508 // nothing to promote 509 return false; 510 } 511 512 // the deferred targets can be generally promoted unless they 513 // contain a cache maintenance request 514 515 // find the first target that is a cache maintenance request 516 auto it = std::find_if(deferredTargets.begin(), deferredTargets.end(), 517 [](MSHR::Target &t) { 518 return t.pkt->req->isCacheMaintenance(); 519 }); 520 if (it == deferredTargets.begin()) { 521 // if the first deferred target is a cache maintenance packet 522 // then we can promote provided the targets list is empty and 523 // we can service it on its own 524 if (targets.empty()) { 525 targets.splice(targets.end(), deferredTargets, it); 526 } 527 } else { 528 // if a cache maintenance operation exists, we promote all the 529 // deferred targets that precede it, or all deferred targets 530 // otherwise 531 targets.splice(targets.end(), deferredTargets, 532 deferredTargets.begin(), it); 533 } 534 535 deferredTargets.populateFlags(); 536 targets.populateFlags(); 537 order = targets.front().order; 538 readyTime = std::max(curTick(), targets.front().readyTime); 539 540 return true; 541} 542 543 544void 545MSHR::promoteWritable() 546{ 547 if (deferredTargets.needsWritable && 548 !(hasPostInvalidate() || hasPostDowngrade())) { 549 // We got a writable response, but we have deferred targets 550 // which are waiting to request a writable copy (not because 551 // of a pending invalidate). This can happen if the original 552 // request was for a read-only block, but we got a writable 553 // response anyway. Since we got the writable copy there's no 554 // need to defer the targets, so move them up to the regular 555 // target list. 556 assert(!targets.needsWritable); 557 targets.needsWritable = true; 558 // if any of the deferred targets were upper-level cache 559 // requests marked downstreamPending, need to clear that 560 assert(!downstreamPending); // not pending here anymore 561 deferredTargets.clearDownstreamPending(); 562 // this clears out deferredTargets too 563 targets.splice(targets.end(), deferredTargets); 564 deferredTargets.resetFlags(); 565 } 566} 567 568 569bool 570MSHR::checkFunctional(PacketPtr pkt) 571{ 572 // For printing, we treat the MSHR as a whole as single entity. 573 // For other requests, we iterate over the individual targets 574 // since that's where the actual data lies. 575 if (pkt->isPrint()) { 576 pkt->checkFunctional(this, blkAddr, isSecure, blkSize, nullptr); 577 return false; 578 } else { 579 return (targets.checkFunctional(pkt) || 580 deferredTargets.checkFunctional(pkt)); 581 } 582} 583 584bool 585MSHR::sendPacket(Cache &cache) 586{ 587 return cache.sendMSHRQueuePacket(this); 588} 589 590void 591MSHR::print(std::ostream &os, int verbosity, const std::string &prefix) const 592{ 593 ccprintf(os, "%s[%#llx:%#llx](%s) %s %s %s state: %s %s %s %s %s\n", 594 prefix, blkAddr, blkAddr + blkSize - 1, 595 isSecure ? "s" : "ns", 596 isForward ? "Forward" : "", 597 allocOnFill() ? "AllocOnFill" : "", 598 needsWritable() ? "Wrtbl" : "", 599 _isUncacheable ? "Unc" : "", 600 inService ? "InSvc" : "", 601 downstreamPending ? "DwnPend" : "", 602 postInvalidate ? "PostInv" : "", 603 postDowngrade ? "PostDowngr" : ""); 604 605 if (!targets.empty()) { 606 ccprintf(os, "%s Targets:\n", prefix); 607 targets.print(os, verbosity, prefix + " "); 608 } 609 if (!deferredTargets.empty()) { 610 ccprintf(os, "%s Deferred Targets:\n", prefix); 611 deferredTargets.print(os, verbosity, prefix + " "); 612 } 613} 614 615std::string 616MSHR::print() const 617{ 618 std::ostringstream str; 619 print(str); 620 return str.str(); 621} 622