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