mshr.cc revision 12715
17405SAli.Saidi@ARM.com/*
210338SCurtis.Dunham@arm.com * Copyright (c) 2012-2013, 2015-2018 ARM Limited
37405SAli.Saidi@ARM.com * All rights reserved.
47405SAli.Saidi@ARM.com *
57405SAli.Saidi@ARM.com * The license below extends only to copyright in the software and shall
67405SAli.Saidi@ARM.com * not be construed as granting a license to any other intellectual
77405SAli.Saidi@ARM.com * property including but not limited to intellectual property relating
87405SAli.Saidi@ARM.com * to a hardware implementation of the functionality of the software
97405SAli.Saidi@ARM.com * licensed hereunder.  You may use the software subject to the license
107405SAli.Saidi@ARM.com * terms below provided that you ensure that this notice is replicated
117405SAli.Saidi@ARM.com * unmodified and in its entirety in all distributions of the software,
127405SAli.Saidi@ARM.com * modified or unmodified, in source code or in binary form.
137405SAli.Saidi@ARM.com *
147405SAli.Saidi@ARM.com * Copyright (c) 2002-2005 The Regents of The University of Michigan
157405SAli.Saidi@ARM.com * Copyright (c) 2010 Advanced Micro Devices, Inc.
167405SAli.Saidi@ARM.com * All rights reserved.
177405SAli.Saidi@ARM.com *
187405SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without
197405SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are
207405SAli.Saidi@ARM.com * met: redistributions of source code must retain the above copyright
217405SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer;
227405SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright
237405SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the
247405SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution;
257405SAli.Saidi@ARM.com * neither the name of the copyright holders nor the names of its
267405SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from
277405SAli.Saidi@ARM.com * this software without specific prior written permission.
287405SAli.Saidi@ARM.com *
297405SAli.Saidi@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
307405SAli.Saidi@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
317405SAli.Saidi@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
327405SAli.Saidi@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
337405SAli.Saidi@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
347405SAli.Saidi@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
357405SAli.Saidi@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
367405SAli.Saidi@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
377405SAli.Saidi@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
387405SAli.Saidi@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
397405SAli.Saidi@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
407405SAli.Saidi@ARM.com *
417405SAli.Saidi@ARM.com * Authors: Erik Hallnor
429050Schander.sudanthi@arm.com *          Dave Greene
438887Sgeoffrey.blake@arm.com */
448232Snate@binkert.org
458232Snate@binkert.org/**
469384SAndreas.Sandberg@arm.com * @file
477678Sgblack@eecs.umich.edu * Miss Status and Handling Register (MSHR) definitions.
488059SAli.Saidi@ARM.com */
498284SAli.Saidi@ARM.com
507405SAli.Saidi@ARM.com#include "mem/cache/mshr.hh"
517405SAli.Saidi@ARM.com
527405SAli.Saidi@ARM.com#include <algorithm>
537405SAli.Saidi@ARM.com#include <cassert>
5410037SARM gem5 Developers#include <string>
5510037SARM gem5 Developers#include <vector>
5610037SARM gem5 Developers
5710037SARM gem5 Developers#include "base/logging.hh"
5810037SARM gem5 Developers#include "base/types.hh"
5910037SARM gem5 Developers#include "debug/Cache.hh"
6010037SARM gem5 Developers#include "mem/cache/cache.hh"
6110037SARM gem5 Developers#include "sim/core.hh"
6210037SARM gem5 Developers
6310037SARM gem5 DevelopersMSHR::MSHR() : downstreamPending(false),
6410037SARM gem5 Developers               pendingModified(false),
6510037SARM gem5 Developers               postInvalidate(false), postDowngrade(false),
6610037SARM gem5 Developers               isForward(false)
6710037SARM gem5 Developers{
6810037SARM gem5 Developers}
6910037SARM gem5 Developers
7010037SARM gem5 DevelopersMSHR::TargetList::TargetList()
7110037SARM gem5 Developers    : needsWritable(false), hasUpgrade(false), allocOnFill(false),
7210037SARM gem5 Developers      hasFromCache(false)
7310037SARM gem5 Developers{}
7410037SARM gem5 Developers
7510037SARM gem5 Developers
7610037SARM gem5 Developersvoid
7710037SARM gem5 DevelopersMSHR::TargetList::updateFlags(PacketPtr pkt, Target::Source source,
7810037SARM gem5 Developers                              bool alloc_on_fill)
7910037SARM gem5 Developers{
8010037SARM gem5 Developers    if (source != Target::FromSnoop) {
8110037SARM gem5 Developers        if (pkt->needsWritable()) {
8210037SARM gem5 Developers            needsWritable = true;
8310037SARM gem5 Developers        }
8410037SARM gem5 Developers
8510037SARM gem5 Developers        // StoreCondReq is effectively an upgrade if it's in an MSHR
8610037SARM gem5 Developers        // since it would have been failed already if we didn't have a
8710037SARM gem5 Developers        // read-only copy
8810037SARM gem5 Developers        if (pkt->isUpgrade() || pkt->cmd == MemCmd::StoreCondReq) {
8910037SARM gem5 Developers            hasUpgrade = true;
9010037SARM gem5 Developers        }
9110037SARM gem5 Developers
9210037SARM gem5 Developers        // potentially re-evaluate whether we should allocate on a fill or
9310037SARM gem5 Developers        // not
9410037SARM gem5 Developers        allocOnFill = allocOnFill || alloc_on_fill;
9510037SARM gem5 Developers
9610037SARM gem5 Developers        if (source != Target::FromPrefetcher) {
9710037SARM gem5 Developers            hasFromCache = hasFromCache || pkt->fromCache();
9810037SARM gem5 Developers        }
9910037SARM gem5 Developers    }
10010037SARM gem5 Developers}
10110037SARM gem5 Developers
10210037SARM gem5 Developersvoid
10310037SARM gem5 DevelopersMSHR::TargetList::populateFlags()
10410037SARM gem5 Developers{
10510037SARM gem5 Developers    resetFlags();
10610037SARM gem5 Developers    for (auto& t: *this) {
10710037SARM gem5 Developers        updateFlags(t.pkt, t.source, t.allocOnFill);
10810037SARM gem5 Developers    }
10910037SARM gem5 Developers}
11010037SARM gem5 Developers
11110037SARM gem5 Developersinline void
11210037SARM gem5 DevelopersMSHR::TargetList::add(PacketPtr pkt, Tick readyTime,
11310037SARM gem5 Developers                      Counter order, Target::Source source, bool markPending,
11410037SARM gem5 Developers                      bool alloc_on_fill)
11510037SARM gem5 Developers{
11610037SARM gem5 Developers    updateFlags(pkt, source, alloc_on_fill);
11710037SARM gem5 Developers    if (markPending) {
11810037SARM gem5 Developers        // Iterate over the SenderState stack and see if we find
11910037SARM gem5 Developers        // an MSHR entry. If we do, set the downstreamPending
12010037SARM gem5 Developers        // flag. Otherwise, do nothing.
12110037SARM gem5 Developers        MSHR *mshr = pkt->findNextSenderState<MSHR>();
12210037SARM gem5 Developers        if (mshr != nullptr) {
12310037SARM gem5 Developers            assert(!mshr->downstreamPending);
1249384SAndreas.Sandberg@arm.com            mshr->downstreamPending = true;
12510037SARM gem5 Developers        } else {
1269384SAndreas.Sandberg@arm.com            // No need to clear downstreamPending later
1279384SAndreas.Sandberg@arm.com            markPending = false;
1289384SAndreas.Sandberg@arm.com        }
1299384SAndreas.Sandberg@arm.com    }
13010037SARM gem5 Developers
13110037SARM gem5 Developers    emplace_back(pkt, readyTime, order, source, markPending, alloc_on_fill);
13210037SARM gem5 Developers}
13310037SARM gem5 Developers
13410037SARM gem5 Developers
13510037SARM gem5 Developersstatic void
13610037SARM gem5 DevelopersreplaceUpgrade(PacketPtr pkt)
13710037SARM gem5 Developers{
13810037SARM gem5 Developers    // remember if the current packet has data allocated
13910037SARM gem5 Developers    bool has_data = pkt->hasData() || pkt->hasRespData();
14010037SARM gem5 Developers
14110037SARM gem5 Developers    if (pkt->cmd == MemCmd::UpgradeReq) {
14210037SARM gem5 Developers        pkt->cmd = MemCmd::ReadExReq;
14310037SARM gem5 Developers        DPRINTF(Cache, "Replacing UpgradeReq with ReadExReq\n");
14410037SARM gem5 Developers    } else if (pkt->cmd == MemCmd::SCUpgradeReq) {
14510037SARM gem5 Developers        pkt->cmd = MemCmd::SCUpgradeFailReq;
14610037SARM gem5 Developers        DPRINTF(Cache, "Replacing SCUpgradeReq with SCUpgradeFailReq\n");
14710037SARM gem5 Developers    } else if (pkt->cmd == MemCmd::StoreCondReq) {
14810037SARM gem5 Developers        pkt->cmd = MemCmd::StoreCondFailReq;
14910037SARM gem5 Developers        DPRINTF(Cache, "Replacing StoreCondReq with StoreCondFailReq\n");
15010037SARM gem5 Developers    }
15110037SARM gem5 Developers
15210037SARM gem5 Developers    if (!has_data) {
15310037SARM gem5 Developers        // there is no sensible way of setting the data field if the
15410037SARM gem5 Developers        // new command actually would carry data
15510037SARM gem5 Developers        assert(!pkt->hasData());
15610037SARM gem5 Developers
15710037SARM gem5 Developers        if (pkt->hasRespData()) {
15810037SARM gem5 Developers            // we went from a packet that had no data (neither request,
1599384SAndreas.Sandberg@arm.com            // nor response), to one that does, and therefore we need to
1609384SAndreas.Sandberg@arm.com            // actually allocate space for the data payload
1619384SAndreas.Sandberg@arm.com            pkt->allocate();
1629384SAndreas.Sandberg@arm.com        }
1639384SAndreas.Sandberg@arm.com    }
1649384SAndreas.Sandberg@arm.com}
1659384SAndreas.Sandberg@arm.com
1669384SAndreas.Sandberg@arm.com
1679384SAndreas.Sandberg@arm.comvoid
1687427Sgblack@eecs.umich.eduMSHR::TargetList::replaceUpgrades()
1697427Sgblack@eecs.umich.edu{
1707427Sgblack@eecs.umich.edu    if (!hasUpgrade)
1719385SAndreas.Sandberg@arm.com        return;
1729385SAndreas.Sandberg@arm.com
1737427Sgblack@eecs.umich.edu    for (auto& t : *this) {
1747427Sgblack@eecs.umich.edu        replaceUpgrade(t.pkt);
17510037SARM gem5 Developers    }
17610037SARM gem5 Developers
17710037SARM gem5 Developers    hasUpgrade = false;
17810037SARM gem5 Developers}
17910037SARM gem5 Developers
18010037SARM gem5 Developers
18110037SARM gem5 Developersvoid
18210037SARM gem5 DevelopersMSHR::TargetList::clearDownstreamPending()
18310037SARM gem5 Developers{
18410037SARM gem5 Developers    for (auto& t : *this) {
18510037SARM gem5 Developers        if (t.markedPending) {
18610037SARM gem5 Developers            // Iterate over the SenderState stack and see if we find
18710037SARM gem5 Developers            // an MSHR entry. If we find one, clear the
18810037SARM gem5 Developers            // downstreamPending flag by calling
1897427Sgblack@eecs.umich.edu            // clearDownstreamPending(). This recursively clears the
1907427Sgblack@eecs.umich.edu            // downstreamPending flag in all caches this packet has
1917427Sgblack@eecs.umich.edu            // passed through.
1927427Sgblack@eecs.umich.edu            MSHR *mshr = t.pkt->findNextSenderState<MSHR>();
1937427Sgblack@eecs.umich.edu            if (mshr != nullptr) {
1947427Sgblack@eecs.umich.edu                mshr->clearDownstreamPending();
19510037SARM gem5 Developers            }
19610037SARM gem5 Developers            t.markedPending = false;
19710037SARM gem5 Developers        }
19810037SARM gem5 Developers    }
1997427Sgblack@eecs.umich.edu}
2007427Sgblack@eecs.umich.edu
2017427Sgblack@eecs.umich.edu
20210037SARM gem5 Developersbool
20310204SAli.Saidi@ARM.comMSHR::TargetList::checkFunctional(PacketPtr pkt)
20410204SAli.Saidi@ARM.com{
20510037SARM gem5 Developers    for (auto& t : *this) {
2067427Sgblack@eecs.umich.edu        if (pkt->checkFunctional(t.pkt)) {
20710037SARM gem5 Developers            return true;
2087427Sgblack@eecs.umich.edu        }
20910037SARM gem5 Developers    }
2107427Sgblack@eecs.umich.edu
2117427Sgblack@eecs.umich.edu    return false;
21210037SARM gem5 Developers}
2137427Sgblack@eecs.umich.edu
2147427Sgblack@eecs.umich.edu
2157427Sgblack@eecs.umich.eduvoid
2167427Sgblack@eecs.umich.eduMSHR::TargetList::print(std::ostream &os, int verbosity,
2177427Sgblack@eecs.umich.edu                        const std::string &prefix) const
2187427Sgblack@eecs.umich.edu{
2197427Sgblack@eecs.umich.edu    for (auto& t : *this) {
2207427Sgblack@eecs.umich.edu        const char *s;
2217427Sgblack@eecs.umich.edu        switch (t.source) {
2227427Sgblack@eecs.umich.edu          case Target::FromCPU:
2237427Sgblack@eecs.umich.edu            s = "FromCPU";
2247427Sgblack@eecs.umich.edu            break;
2257427Sgblack@eecs.umich.edu          case Target::FromSnoop:
2267427Sgblack@eecs.umich.edu            s = "FromSnoop";
2277427Sgblack@eecs.umich.edu            break;
2287427Sgblack@eecs.umich.edu          case Target::FromPrefetcher:
2297427Sgblack@eecs.umich.edu            s = "FromPrefetcher";
2307427Sgblack@eecs.umich.edu            break;
2317427Sgblack@eecs.umich.edu          default:
2327427Sgblack@eecs.umich.edu            s = "";
2337427Sgblack@eecs.umich.edu            break;
2347427Sgblack@eecs.umich.edu        }
2357427Sgblack@eecs.umich.edu        ccprintf(os, "%s%s: ", prefix, s);
2367436Sdam.sunwoo@arm.com        t.pkt->print(os, verbosity, "");
2377436Sdam.sunwoo@arm.com        ccprintf(os, "\n");
23810037SARM gem5 Developers    }
23910037SARM gem5 Developers}
2407436Sdam.sunwoo@arm.com
2417436Sdam.sunwoo@arm.com
2427436Sdam.sunwoo@arm.comvoid
2437436Sdam.sunwoo@arm.comMSHR::allocate(Addr blk_addr, unsigned blk_size, PacketPtr target,
2447436Sdam.sunwoo@arm.com               Tick when_ready, Counter _order, bool alloc_on_fill)
2457436Sdam.sunwoo@arm.com{
2467436Sdam.sunwoo@arm.com    blkAddr = blk_addr;
2477436Sdam.sunwoo@arm.com    blkSize = blk_size;
2487436Sdam.sunwoo@arm.com    isSecure = target->isSecure();
2497436Sdam.sunwoo@arm.com    readyTime = when_ready;
2507436Sdam.sunwoo@arm.com    order = _order;
2517436Sdam.sunwoo@arm.com    assert(target);
25210037SARM gem5 Developers    isForward = false;
2537436Sdam.sunwoo@arm.com    _isUncacheable = target->req->isUncacheable();
2547436Sdam.sunwoo@arm.com    inService = false;
2557436Sdam.sunwoo@arm.com    downstreamPending = false;
2567436Sdam.sunwoo@arm.com    assert(targets.isReset());
2577436Sdam.sunwoo@arm.com    // Don't know of a case where we would allocate a new MSHR for a
2587436Sdam.sunwoo@arm.com    // snoop (mem-side request), so set source according to request here
2597436Sdam.sunwoo@arm.com    Target::Source source = (target->cmd == MemCmd::HardPFReq) ?
2607436Sdam.sunwoo@arm.com        Target::FromPrefetcher : Target::FromCPU;
2617436Sdam.sunwoo@arm.com    targets.add(target, when_ready, _order, source, true, alloc_on_fill);
2627436Sdam.sunwoo@arm.com    assert(deferredTargets.isReset());
2637436Sdam.sunwoo@arm.com}
2647436Sdam.sunwoo@arm.com
2657436Sdam.sunwoo@arm.com
2667436Sdam.sunwoo@arm.comvoid
2677436Sdam.sunwoo@arm.comMSHR::clearDownstreamPending()
2687436Sdam.sunwoo@arm.com{
2697644Sali.saidi@arm.com    assert(downstreamPending);
2708147SAli.Saidi@ARM.com    downstreamPending = false;
2719385SAndreas.Sandberg@arm.com    // recursively clear flag on any MSHRs we will be forwarding
2729385SAndreas.Sandberg@arm.com    // responses to
2739385SAndreas.Sandberg@arm.com    targets.clearDownstreamPending();
2749385SAndreas.Sandberg@arm.com}
2759385SAndreas.Sandberg@arm.com
2769385SAndreas.Sandberg@arm.comvoid
2779385SAndreas.Sandberg@arm.comMSHR::markInService(bool pending_modified_resp)
2789385SAndreas.Sandberg@arm.com{
2799385SAndreas.Sandberg@arm.com    assert(!inService);
2809385SAndreas.Sandberg@arm.com
2819385SAndreas.Sandberg@arm.com    inService = true;
2829385SAndreas.Sandberg@arm.com    pendingModified = targets.needsWritable || pending_modified_resp;
2839385SAndreas.Sandberg@arm.com    postInvalidate = postDowngrade = false;
2849385SAndreas.Sandberg@arm.com
2859385SAndreas.Sandberg@arm.com    if (!downstreamPending) {
2869385SAndreas.Sandberg@arm.com        // let upstream caches know that the request has made it to a
2879385SAndreas.Sandberg@arm.com        // level where it's going to get a response
2889385SAndreas.Sandberg@arm.com        targets.clearDownstreamPending();
28910037SARM gem5 Developers    }
29010037SARM gem5 Developers}
29110037SARM gem5 Developers
29210037SARM gem5 Developers
29310037SARM gem5 Developersvoid
29410037SARM gem5 DevelopersMSHR::deallocate()
29510037SARM gem5 Developers{
29610037SARM gem5 Developers    assert(targets.empty());
29710037SARM gem5 Developers    targets.resetFlags();
29810037SARM gem5 Developers    assert(deferredTargets.isReset());
29910037SARM gem5 Developers    inService = false;
30010037SARM gem5 Developers}
30110037SARM gem5 Developers
30210037SARM gem5 Developers/*
30310037SARM gem5 Developers * Adds a target to an MSHR
30410037SARM gem5 Developers */
3058147SAli.Saidi@ARM.comvoid
3067427Sgblack@eecs.umich.eduMSHR::allocateTarget(PacketPtr pkt, Tick whenReady, Counter _order,
3077427Sgblack@eecs.umich.edu                     bool alloc_on_fill)
3087427Sgblack@eecs.umich.edu{
30910037SARM gem5 Developers    // assume we'd never issue a prefetch when we've got an
31010037SARM gem5 Developers    // outstanding miss
31110037SARM gem5 Developers    assert(pkt->cmd != MemCmd::HardPFReq);
31210037SARM gem5 Developers
31310037SARM gem5 Developers    // uncacheable accesses always allocate a new MSHR, and cacheable
31410037SARM gem5 Developers    // accesses ignore any uncacheable MSHRs, thus we should never
31510037SARM gem5 Developers    // have targets addded if originally allocated uncacheable
31610037SARM gem5 Developers    assert(!_isUncacheable);
31710037SARM gem5 Developers
31810037SARM gem5 Developers    // if there's a request already in service for this MSHR, we will
31910037SARM gem5 Developers    // have to defer the new target until after the response if any of
32010037SARM gem5 Developers    // the following are true:
32110037SARM gem5 Developers    // - there are other targets already deferred
32210037SARM gem5 Developers    // - there's a pending invalidate to be applied after the response
32310037SARM gem5 Developers    //   comes back (but before this target is processed)
32410037SARM gem5 Developers    // - the MSHR's first (and only) non-deferred target is a cache
32510037SARM gem5 Developers    //   maintenance packet
32610037SARM gem5 Developers    // - the new target is a cache maintenance packet (this is probably
32710037SARM gem5 Developers    //   overly conservative but certainly safe)
32810037SARM gem5 Developers    // - this target requires a writable block and either we're not
32910037SARM gem5 Developers    //   getting a writable block back or we have already snooped
33010037SARM gem5 Developers    //   another read request that will downgrade our writable block
33110037SARM gem5 Developers    //   to non-writable (Shared or Owned)
33210037SARM gem5 Developers    PacketPtr tgt_pkt = targets.front().pkt;
33310037SARM gem5 Developers    if (pkt->req->isCacheMaintenance() ||
33410037SARM gem5 Developers        tgt_pkt->req->isCacheMaintenance() ||
33510037SARM gem5 Developers        !deferredTargets.empty() ||
33610037SARM gem5 Developers        (inService &&
33710037SARM gem5 Developers         (hasPostInvalidate() ||
33810037SARM gem5 Developers          (pkt->needsWritable() &&
33910037SARM gem5 Developers           (!isPendingModified() || hasPostDowngrade() || isForward))))) {
34010037SARM gem5 Developers        // need to put on deferred list
34110037SARM gem5 Developers        if (inService && hasPostInvalidate())
34210037SARM gem5 Developers            replaceUpgrade(pkt);
34310037SARM gem5 Developers        deferredTargets.add(pkt, whenReady, _order, Target::FromCPU, true,
34410037SARM gem5 Developers                            alloc_on_fill);
34510037SARM gem5 Developers    } else {
34610037SARM gem5 Developers        // No request outstanding, or still OK to append to
34710037SARM gem5 Developers        // outstanding request: append to regular target list.  Only
34810037SARM gem5 Developers        // mark pending if current request hasn't been issued yet
34910037SARM gem5 Developers        // (isn't in service).
35010037SARM gem5 Developers        targets.add(pkt, whenReady, _order, Target::FromCPU, !inService,
35110037SARM gem5 Developers                    alloc_on_fill);
35210037SARM gem5 Developers    }
35310037SARM gem5 Developers}
35410037SARM gem5 Developers
35510037SARM gem5 Developersbool
35610037SARM gem5 DevelopersMSHR::handleSnoop(PacketPtr pkt, Counter _order)
35710037SARM gem5 Developers{
35810037SARM gem5 Developers    DPRINTF(Cache, "%s for %s\n", __func__, pkt->print());
35910037SARM gem5 Developers
36010037SARM gem5 Developers    // when we snoop packets the needsWritable and isInvalidate flags
36110037SARM gem5 Developers    // should always be the same, however, this assumes that we never
36210037SARM gem5 Developers    // snoop writes as they are currently not marked as invalidations
36310037SARM gem5 Developers    panic_if((pkt->needsWritable() != pkt->isInvalidate()) &&
36410037SARM gem5 Developers             !pkt->req->isCacheMaintenance(),
36510037SARM gem5 Developers             "%s got snoop %s where needsWritable, "
36610037SARM gem5 Developers             "does not match isInvalidate", name(), pkt->print());
36710037SARM gem5 Developers
36810037SARM gem5 Developers    if (!inService || (pkt->isExpressSnoop() && downstreamPending)) {
36910037SARM gem5 Developers        // Request has not been issued yet, or it's been issued
37010037SARM gem5 Developers        // locally but is buffered unissued at some downstream cache
37110037SARM gem5 Developers        // which is forwarding us this snoop.  Either way, the packet
37210037SARM gem5 Developers        // we're snooping logically precedes this MSHR's request, so
37310037SARM gem5 Developers        // the snoop has no impact on the MSHR, but must be processed
37410037SARM gem5 Developers        // in the standard way by the cache.  The only exception is
37510037SARM gem5 Developers        // that if we're an L2+ cache buffering an UpgradeReq from a
37610037SARM gem5 Developers        // higher-level cache, and the snoop is invalidating, then our
37710037SARM gem5 Developers        // buffered upgrades must be converted to read exclusives,
37810037SARM gem5 Developers        // since the upper-level cache no longer has a valid copy.
37910037SARM gem5 Developers        // That is, even though the upper-level cache got out on its
38010037SARM gem5 Developers        // local bus first, some other invalidating transaction
38110037SARM gem5 Developers        // reached the global bus before the upgrade did.
38210037SARM gem5 Developers        if (pkt->needsWritable() || pkt->req->isCacheInvalidate()) {
38310037SARM gem5 Developers            targets.replaceUpgrades();
38410037SARM gem5 Developers            deferredTargets.replaceUpgrades();
38510037SARM gem5 Developers        }
38610037SARM gem5 Developers
38710037SARM gem5 Developers        return false;
38810037SARM gem5 Developers    }
38910037SARM gem5 Developers
3907405SAli.Saidi@ARM.com    // From here on down, the request issued by this MSHR logically
39110035Sandreas.hansson@arm.com    // precedes the request we're snooping.
3927405SAli.Saidi@ARM.com    if (pkt->needsWritable() || pkt->req->isCacheInvalidate()) {
3937405SAli.Saidi@ARM.com        // snooped request still precedes the re-request we'll have to
3947614Sminkyu.jeong@arm.com        // issue for deferred targets, if any...
39510037SARM gem5 Developers        deferredTargets.replaceUpgrades();
39610037SARM gem5 Developers    }
39710037SARM gem5 Developers
3987614Sminkyu.jeong@arm.com    PacketPtr tgt_pkt = targets.front().pkt;
39910037SARM gem5 Developers    if (hasPostInvalidate() || tgt_pkt->req->isCacheInvalidate()) {
40010037SARM gem5 Developers        // a prior snoop has already appended an invalidation or a
40110037SARM gem5 Developers        // cache invalidation operation is in progress, so logically
40210037SARM gem5 Developers        // we don't have the block anymore; no need for further
40310037SARM gem5 Developers        // snooping.
40410037SARM gem5 Developers        return true;
40510037SARM gem5 Developers    }
40610037SARM gem5 Developers
40710037SARM gem5 Developers    if (isPendingModified() || pkt->isInvalidate()) {
40810037SARM gem5 Developers        // We need to save and replay the packet in two cases:
40910037SARM gem5 Developers        // 1. We're awaiting a writable copy (Modified or Exclusive),
41010037SARM gem5 Developers        //    so this MSHR is the orgering point, and we need to respond
41110037SARM gem5 Developers        //    after we receive data.
41210037SARM gem5 Developers        // 2. It's an invalidation (e.g., UpgradeReq), and we need
4137614Sminkyu.jeong@arm.com        //    to forward the snoop up the hierarchy after the current
4147405SAli.Saidi@ARM.com        //    transaction completes.
4157405SAli.Saidi@ARM.com
4167405SAli.Saidi@ARM.com        // Start by determining if we will eventually respond or not,
4177405SAli.Saidi@ARM.com        // matching the conditions checked in Cache::handleSnoop
4187405SAli.Saidi@ARM.com        bool will_respond = isPendingModified() && pkt->needsResponse() &&
4197405SAli.Saidi@ARM.com                      !pkt->isClean();
42010037SARM gem5 Developers
42110037SARM gem5 Developers        // The packet we are snooping may be deleted by the time we
42210037SARM gem5 Developers        // actually process the target, and we consequently need to
4239050Schander.sudanthi@arm.com        // save a copy here. Clear flags and also allocate new data as
4247405SAli.Saidi@ARM.com        // the original packet data storage may have been deleted by
42510037SARM gem5 Developers        // the time we get to process this packet. In the cases where
42610037SARM gem5 Developers        // we are not responding after handling the snoop we also need
4277720Sgblack@eecs.umich.edu        // to create a copy of the request to be on the safe side. In
4287720Sgblack@eecs.umich.edu        // the latter case the cache is responsible for deleting both
4297405SAli.Saidi@ARM.com        // the packet and the request as part of handling the deferred
4307405SAli.Saidi@ARM.com        // snoop.
4317757SAli.Saidi@ARM.com        PacketPtr cp_pkt = will_respond ? new Packet(pkt, true, true) :
43210037SARM gem5 Developers            new Packet(new Request(*pkt->req), pkt->cmd, blkSize, pkt->id);
43310037SARM gem5 Developers
43410037SARM gem5 Developers        if (will_respond) {
43510037SARM gem5 Developers            // we are the ordering point, and will consequently
43610037SARM gem5 Developers            // respond, and depending on whether the packet
43710037SARM gem5 Developers            // needsWritable or not we either pass a Shared line or a
43810037SARM gem5 Developers            // Modified line
43910037SARM gem5 Developers            pkt->setCacheResponding();
44010037SARM gem5 Developers
44110037SARM gem5 Developers            // inform the cache hierarchy that this cache had the line
44210037SARM gem5 Developers            // in the Modified state, even if the response is passed
44310037SARM gem5 Developers            // as Shared (and thus non-writable)
44410037SARM gem5 Developers            pkt->setResponderHadWritable();
44510037SARM gem5 Developers
44610037SARM gem5 Developers            // in the case of an uncacheable request there is no need
44710037SARM gem5 Developers            // to set the responderHadWritable flag, but since the
44810037SARM gem5 Developers            // recipient does not care there is no harm in doing so
44910037SARM gem5 Developers        }
45010037SARM gem5 Developers        targets.add(cp_pkt, curTick(), _order, Target::FromSnoop,
45110037SARM gem5 Developers                    downstreamPending && targets.needsWritable, false);
45210037SARM gem5 Developers
45310037SARM gem5 Developers        if (pkt->needsWritable() || pkt->isInvalidate()) {
45410037SARM gem5 Developers            // This transaction will take away our pending copy
45510037SARM gem5 Developers            postInvalidate = true;
45610037SARM gem5 Developers        }
45710037SARM gem5 Developers
45810037SARM gem5 Developers        if (isPendingModified() && pkt->isClean()) {
45910037SARM gem5 Developers            pkt->setSatisfied();
46010037SARM gem5 Developers        }
46110037SARM gem5 Developers    }
46210037SARM gem5 Developers
46310037SARM gem5 Developers    if (!pkt->needsWritable() && !pkt->req->isUncacheable()) {
46410037SARM gem5 Developers        // This transaction will get a read-shared copy, downgrading
46510037SARM gem5 Developers        // our copy if we had a writable one
46610037SARM gem5 Developers        postDowngrade = true;
46710037SARM gem5 Developers        // make sure that any downstream cache does not respond with a
46810037SARM gem5 Developers        // writable (and dirty) copy even if it has one, unless it was
46910037SARM gem5 Developers        // explicitly asked for one
47010037SARM gem5 Developers        pkt->setHasSharers();
47110037SARM gem5 Developers    }
47210037SARM gem5 Developers
47310037SARM gem5 Developers    return true;
47410037SARM gem5 Developers}
47510037SARM gem5 Developers
47610037SARM gem5 DevelopersMSHR::TargetList
47710037SARM gem5 DevelopersMSHR::extractServiceableTargets(PacketPtr pkt)
4788284SAli.Saidi@ARM.com{
47910037SARM gem5 Developers    TargetList ready_targets;
48010037SARM gem5 Developers    // If the downstream MSHR got an invalidation request then we only
48110037SARM gem5 Developers    // service the first of the FromCPU targets and any other
48210037SARM gem5 Developers    // non-FromCPU target. This way the remaining FromCPU targets
4839050Schander.sudanthi@arm.com    // issue a new request and get a fresh copy of the block and we
48410037SARM gem5 Developers    // avoid memory consistency violations.
48510037SARM gem5 Developers    if (pkt->cmd == MemCmd::ReadRespWithInvalidate) {
48610037SARM gem5 Developers        auto it = targets.begin();
48710037SARM gem5 Developers        assert((it->source == Target::FromCPU) ||
48810037SARM gem5 Developers               (it->source == Target::FromPrefetcher));
48910037SARM gem5 Developers        ready_targets.push_back(*it);
49010037SARM gem5 Developers        it = targets.erase(it);
49110037SARM gem5 Developers        while (it != targets.end()) {
49210037SARM gem5 Developers            if (it->source == Target::FromCPU) {
49310037SARM gem5 Developers                it++;
49410037SARM gem5 Developers            } else {
49510037SARM gem5 Developers                assert(it->source == Target::FromSnoop);
49610037SARM gem5 Developers                ready_targets.push_back(*it);
49710037SARM gem5 Developers                it = targets.erase(it);
49810037SARM gem5 Developers            }
49910037SARM gem5 Developers        }
50010037SARM gem5 Developers        ready_targets.populateFlags();
50110037SARM gem5 Developers    } else {
50210037SARM gem5 Developers        std::swap(ready_targets, targets);
5039050Schander.sudanthi@arm.com    }
5048284SAli.Saidi@ARM.com    targets.populateFlags();
50510037SARM gem5 Developers
50610037SARM gem5 Developers    return ready_targets;
50710037SARM gem5 Developers}
50810037SARM gem5 Developers
50910037SARM gem5 Developersbool
51010037SARM gem5 DevelopersMSHR::promoteDeferredTargets()
51110037SARM gem5 Developers{
5127405SAli.Saidi@ARM.com    if (targets.empty() && deferredTargets.empty()) {
5137731SAli.Saidi@ARM.com        // nothing to promote
5148468Swade.walker@arm.com        return false;
5158468Swade.walker@arm.com    }
5168468Swade.walker@arm.com
5177405SAli.Saidi@ARM.com    // the deferred targets can be generally promoted unless they
5187731SAli.Saidi@ARM.com    // contain a cache maintenance request
5197405SAli.Saidi@ARM.com
5207405SAli.Saidi@ARM.com    // find the first target that is a cache maintenance request
5217583SAli.Saidi@arm.com    auto it = std::find_if(deferredTargets.begin(), deferredTargets.end(),
5229130Satgutier@umich.edu                           [](MSHR::Target &t) {
5239130Satgutier@umich.edu                               return t.pkt->req->isCacheMaintenance();
5249130Satgutier@umich.edu                           });
5259130Satgutier@umich.edu    if (it == deferredTargets.begin()) {
5269814Sandreas.hansson@arm.com        // if the first deferred target is a cache maintenance packet
5279130Satgutier@umich.edu        // then we can promote provided the targets list is empty and
5289130Satgutier@umich.edu        // we can service it on its own
5299130Satgutier@umich.edu        if (targets.empty()) {
5309130Satgutier@umich.edu            targets.splice(targets.end(), deferredTargets, it);
5319130Satgutier@umich.edu        }
5329130Satgutier@umich.edu    } else {
5339130Satgutier@umich.edu        // if a cache maintenance operation exists, we promote all the
5349130Satgutier@umich.edu        // deferred targets that precede it, or all deferred targets
5359130Satgutier@umich.edu        // otherwise
5369130Satgutier@umich.edu        targets.splice(targets.end(), deferredTargets,
5379130Satgutier@umich.edu                       deferredTargets.begin(), it);
5389130Satgutier@umich.edu    }
5399130Satgutier@umich.edu
5409130Satgutier@umich.edu    deferredTargets.populateFlags();
5419130Satgutier@umich.edu    targets.populateFlags();
5429130Satgutier@umich.edu    order = targets.front().order;
5439130Satgutier@umich.edu    readyTime = std::max(curTick(), targets.front().readyTime);
5449130Satgutier@umich.edu
5459130Satgutier@umich.edu    return true;
5469130Satgutier@umich.edu}
5479130Satgutier@umich.edu
5489130Satgutier@umich.edu
5497583SAli.Saidi@arm.comvoid
5507583SAli.Saidi@arm.comMSHR::promoteWritable()
5517583SAli.Saidi@arm.com{
5527583SAli.Saidi@arm.com    if (deferredTargets.needsWritable &&
5537583SAli.Saidi@arm.com        !(hasPostInvalidate() || hasPostDowngrade())) {
5547583SAli.Saidi@arm.com        // We got a writable response, but we have deferred targets
5558299Schander.sudanthi@arm.com        // which are waiting to request a writable copy (not because
5567583SAli.Saidi@arm.com        // of a pending invalidate).  This can happen if the original
5577583SAli.Saidi@arm.com        // request was for a read-only block, but we got a writable
5588302SAli.Saidi@ARM.com        // response anyway. Since we got the writable copy there's no
5598302SAli.Saidi@ARM.com        // need to defer the targets, so move them up to the regular
5607783SGiacomo.Gabrielli@arm.com        // target list.
5617783SGiacomo.Gabrielli@arm.com        assert(!targets.needsWritable);
5627783SGiacomo.Gabrielli@arm.com        targets.needsWritable = true;
5637783SGiacomo.Gabrielli@arm.com        // if any of the deferred targets were upper-level cache
56410037SARM gem5 Developers        // requests marked downstreamPending, need to clear that
56510037SARM gem5 Developers        assert(!downstreamPending);  // not pending here anymore
56610037SARM gem5 Developers        deferredTargets.clearDownstreamPending();
56710037SARM gem5 Developers        // this clears out deferredTargets too
56810037SARM gem5 Developers        targets.splice(targets.end(), deferredTargets);
56910037SARM gem5 Developers        deferredTargets.resetFlags();
57010037SARM gem5 Developers    }
57110037SARM gem5 Developers}
57210037SARM gem5 Developers
57310037SARM gem5 Developers
57410037SARM gem5 Developersbool
57510037SARM gem5 DevelopersMSHR::checkFunctional(PacketPtr pkt)
57610037SARM gem5 Developers{
57710037SARM gem5 Developers    // For printing, we treat the MSHR as a whole as single entity.
57810037SARM gem5 Developers    // For other requests, we iterate over the individual targets
57910037SARM gem5 Developers    // since that's where the actual data lies.
58010037SARM gem5 Developers    if (pkt->isPrint()) {
58110037SARM gem5 Developers        pkt->checkFunctional(this, blkAddr, isSecure, blkSize, nullptr);
58210037SARM gem5 Developers        return false;
58310037SARM gem5 Developers    } else {
58410037SARM gem5 Developers        return (targets.checkFunctional(pkt) ||
58510037SARM gem5 Developers                deferredTargets.checkFunctional(pkt));
58610037SARM gem5 Developers    }
58710037SARM gem5 Developers}
58810037SARM gem5 Developers
58910037SARM gem5 Developersbool
59010037SARM gem5 DevelopersMSHR::sendPacket(Cache &cache)
59110037SARM gem5 Developers{
59210037SARM gem5 Developers    return cache.sendMSHRQueuePacket(this);
59310037SARM gem5 Developers}
59410037SARM gem5 Developers
59510037SARM gem5 Developersvoid
59610037SARM gem5 DevelopersMSHR::print(std::ostream &os, int verbosity, const std::string &prefix) const
59710037SARM gem5 Developers{
59810037SARM gem5 Developers    ccprintf(os, "%s[%#llx:%#llx](%s) %s %s %s state: %s %s %s %s %s %s\n",
59910037SARM gem5 Developers             prefix, blkAddr, blkAddr + blkSize - 1,
60010037SARM gem5 Developers             isSecure ? "s" : "ns",
60110037SARM gem5 Developers             isForward ? "Forward" : "",
60210338SCurtis.Dunham@arm.com             allocOnFill() ? "AllocOnFill" : "",
60310338SCurtis.Dunham@arm.com             needsWritable() ? "Wrtbl" : "",
60410338SCurtis.Dunham@arm.com             _isUncacheable ? "Unc" : "",
60510037SARM gem5 Developers             inService ? "InSvc" : "",
60610037SARM gem5 Developers             downstreamPending ? "DwnPend" : "",
60710037SARM gem5 Developers             postInvalidate ? "PostInv" : "",
60810037SARM gem5 Developers             postDowngrade ? "PostDowngr" : "",
60910037SARM gem5 Developers             hasFromCache() ? "HasFromCache" : "");
61010037SARM gem5 Developers
61110037SARM gem5 Developers    if (!targets.empty()) {
61210037SARM gem5 Developers        ccprintf(os, "%s  Targets:\n", prefix);
61310037SARM gem5 Developers        targets.print(os, verbosity, prefix + "    ");
61410037SARM gem5 Developers    }
61510037SARM gem5 Developers    if (!deferredTargets.empty()) {
61610037SARM gem5 Developers        ccprintf(os, "%s  Deferred Targets:\n", prefix);
61710037SARM gem5 Developers        deferredTargets.print(os, verbosity, prefix + "      ");
61810037SARM gem5 Developers    }
61910037SARM gem5 Developers}
62010037SARM gem5 Developers
62110037SARM gem5 Developersstd::string
62210037SARM gem5 DevelopersMSHR::print() const
62310037SARM gem5 Developers{
62410037SARM gem5 Developers    std::ostringstream str;
62510037SARM gem5 Developers    print(str);
62610037SARM gem5 Developers    return str.str();
62710037SARM gem5 Developers}
62810037SARM gem5 Developers