coherent_xbar.cc revision 9278
15703SN/A/*
25703SN/A * Copyright (c) 2011-2012 ARM Limited
35703SN/A * All rights reserved
49988Snilay@cs.wisc.edu *
58825Snilay@cs.wisc.edu * The license below extends only to copyright in the software and shall
69988Snilay@cs.wisc.edu * not be construed as granting a license to any other intellectual
77935SN/A * property including but not limited to intellectual property relating
87935SN/A * to a hardware implementation of the functionality of the software
97935SN/A * licensed hereunder.  You may use the software subject to the license
105703SN/A * terms below provided that you ensure that this notice is replicated
115703SN/A * unmodified and in its entirety in all distributions of the software,
125703SN/A * modified or unmodified, in source code or in binary form.
1310315Snilay@cs.wisc.edu *
145703SN/A * Copyright (c) 2006 The Regents of The University of Michigan
155703SN/A * All rights reserved.
169885Sstever@gmail.com *
179885Sstever@gmail.com * Redistribution and use in source and binary forms, with or without
1811570SCurtis.Dunham@arm.com * modification, are permitted provided that the following conditions are
1911570SCurtis.Dunham@arm.com * met: redistributions of source code must retain the above copyright
209988Snilay@cs.wisc.edu * notice, this list of conditions and the following disclaimer;
2111570SCurtis.Dunham@arm.com * redistributions in binary form must reproduce the above copyright
225703SN/A * notice, this list of conditions and the following disclaimer in the
2311570SCurtis.Dunham@arm.com * documentation and/or other materials provided with the distribution;
2410315Snilay@cs.wisc.edu * neither the name of the copyright holders nor the names of its
257670SN/A * contributors may be used to endorse or promote products derived from
2610242Ssteve.reinhardt@amd.com * this software without specific prior written permission.
275703SN/A *
2811680SCurtis.Dunham@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
298464SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3010798Ssteve.reinhardt@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3111245Sandreas.sandberg@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
328721SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3311570SCurtis.Dunham@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3411570SCurtis.Dunham@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3511570SCurtis.Dunham@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3611570SCurtis.Dunham@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3711570SCurtis.Dunham@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3811570SCurtis.Dunham@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
395703SN/A *
405703SN/A * Authors: Ali Saidi
415703SN/A *          Andreas Hansson
4211570SCurtis.Dunham@arm.com *          William Wang
4311570SCurtis.Dunham@arm.com */
447935SN/A
457935SN/A/**
467935SN/A * @file
477935SN/A * Definition of a bus object.
487935SN/A */
497935SN/A
507935SN/A#include "base/misc.hh"
518983Snate@binkert.org#include "base/trace.hh"
525703SN/A#include "debug/BusAddrRanges.hh"
535703SN/A#include "debug/CoherentBus.hh"
545703SN/A#include "mem/coherent_bus.hh"
559885Sstever@gmail.com
5611570SCurtis.Dunham@arm.comCoherentBus::CoherentBus(const CoherentBusParams *p)
575703SN/A    : BaseBus(p), reqLayer(*this, ".reqLayer", p->clock),
589988Snilay@cs.wisc.edu      respLayer(*this, ".respLayer", p->clock),
5911570SCurtis.Dunham@arm.com      snoopRespLayer(*this, ".snoopRespLayer", p->clock)
6011570SCurtis.Dunham@arm.com{
6111570SCurtis.Dunham@arm.com    // create the ports based on the size of the master and slave
6211570SCurtis.Dunham@arm.com    // vector ports, and the presence of the default port, the ports
6311680SCurtis.Dunham@arm.com    // are enumerated starting from zero
648721SN/A    for (int i = 0; i < p->port_master_connection_count; ++i) {
658721SN/A        std::string portName = csprintf("%s.master[%d]", name(), i);
668983Snate@binkert.org        MasterPort* bp = new CoherentBusMasterPort(portName, *this, i);
678983Snate@binkert.org        masterPorts.push_back(bp);
685703SN/A    }
699885Sstever@gmail.com
709885Sstever@gmail.com    // see if we have a default slave device connected and if so add
719885Sstever@gmail.com    // our corresponding master port
7210315Snilay@cs.wisc.edu    if (p->port_default_connection_count) {
739988Snilay@cs.wisc.edu        defaultPortID = masterPorts.size();
7410315Snilay@cs.wisc.edu        std::string portName = name() + ".default";
759885Sstever@gmail.com        MasterPort* bp = new CoherentBusMasterPort(portName, *this,
769885Sstever@gmail.com                                                   defaultPortID);
775703SN/A        masterPorts.push_back(bp);
785703SN/A    }
799481Snilay@cs.wisc.edu
805703SN/A    // create the slave ports, once again starting at zero
815703SN/A    for (int i = 0; i < p->port_slave_connection_count; ++i) {
828241SN/A        std::string portName = csprintf("%s.slave[%d]", name(), i);
838241SN/A        SlavePort* bp = new CoherentBusSlavePort(portName, *this, i);
845703SN/A        slavePorts.push_back(bp);
855703SN/A    }
865703SN/A
875703SN/A    clearPortCache();
889481Snilay@cs.wisc.edu}
895703SN/A
905876SN/Avoid
919885Sstever@gmail.comCoherentBus::init()
925703SN/A{
935703SN/A    // the base class is responsible for determining the block size
945703SN/A    BaseBus::init();
955703SN/A
965703SN/A    // iterate over our slave ports and determine which of our
975703SN/A    // neighbouring master ports are snooping and add them as snoopers
985703SN/A    for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end();
995703SN/A         ++p) {
1005703SN/A        // check if the connected master port is snooping
10111570SCurtis.Dunham@arm.com        if ((*p)->isSnooping()) {
1025703SN/A            DPRINTF(BusAddrRanges, "Adding snooping master %s\n",
1035703SN/A                    (*p)->getMasterPort().name());
1045703SN/A            snoopPorts.push_back(*p);
1055703SN/A        }
1065703SN/A    }
1079988Snilay@cs.wisc.edu
1089988Snilay@cs.wisc.edu    if (snoopPorts.empty())
10910451Snilay@cs.wisc.edu        warn("CoherentBus %s has no snooping ports attached!\n", name());
1105703SN/A}
1115703SN/A
1125703SN/Abool
1135703SN/ACoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
1145703SN/A{
1155703SN/A    // determine the source port based on the id
1165703SN/A    SlavePort *src_port = slavePorts[slave_port_id];
1175703SN/A
1185703SN/A    // remember if the packet is an express snoop
1195703SN/A    bool is_express_snoop = pkt->isExpressSnoop();
1205703SN/A
1215703SN/A    // test if the bus should be considered occupied for the current
1229348SAli.Saidi@ARM.com    // port, and exclude express snoops from the check
1235703SN/A    if (!is_express_snoop && !reqLayer.tryTiming(src_port)) {
1245703SN/A        DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x BUSY\n",
1255703SN/A                src_port->name(), pkt->cmdString(), pkt->getAddr());
1265703SN/A        return false;
1275703SN/A    }
1285703SN/A
1295703SN/A    DPRINTF(CoherentBus, "recvTimingReq: src %s %s expr %d 0x%x\n",
1308825Snilay@cs.wisc.edu            src_port->name(), pkt->cmdString(), is_express_snoop,
1315703SN/A            pkt->getAddr());
1329924Ssteve.reinhardt@amd.com
1335703SN/A    // set the source port for routing of the response
1345703SN/A    pkt->setSrc(slave_port_id);
1355703SN/A
1365703SN/A    Tick headerFinishTime = is_express_snoop ? 0 : calcPacketTiming(pkt);
1375703SN/A    Tick packetFinishTime = is_express_snoop ? 0 : pkt->finishTime;
13811570SCurtis.Dunham@arm.com
13911570SCurtis.Dunham@arm.com    // uncacheable requests need never be snooped
14011570SCurtis.Dunham@arm.com    if (!pkt->req->isUncacheable()) {
14111570SCurtis.Dunham@arm.com        // the packet is a memory-mapped request and should be
1425703SN/A        // broadcasted to our snoopers but the source
1435703SN/A        forwardTiming(pkt, slave_port_id);
1445703SN/A    }
1455703SN/A
1465703SN/A    // remember if we add an outstanding req so we can undo it if
1475703SN/A    // necessary, if the packet needs a response, we should add it
1485703SN/A    // as outstanding and express snoops never fail so there is
1499661SAli.Saidi@ARM.com    // not need to worry about them
1505703SN/A    bool add_outstanding = !is_express_snoop && pkt->needsResponse();
1515703SN/A
1525703SN/A    // keep track that we have an outstanding request packet
1535703SN/A    // matching this request, this is used by the coherency
1545703SN/A    // mechanism in determining what to do with snoop responses
1555703SN/A    // (in recvTimingSnoop)
1565703SN/A    if (add_outstanding) {
1575703SN/A        // we should never have an exsiting request outstanding
1585703SN/A        assert(outstandingReq.find(pkt->req) == outstandingReq.end());
15910242Ssteve.reinhardt@amd.com        outstandingReq.insert(pkt->req);
1605703SN/A    }
1618521SN/A
1629449SAli.Saidi@ARM.com    // since it is a normal request, determine the destination
1635703SN/A    // based on the address and attempt to send the packet
1645703SN/A    bool success = masterPorts[findPort(pkt->getAddr())]->sendTimingReq(pkt);
1655703SN/A
1665703SN/A    // if this is an express snoop, we are done at this point
1678825Snilay@cs.wisc.edu    if (is_express_snoop) {
1685703SN/A        assert(success);
1695703SN/A    } else {
1705703SN/A        // for normal requests, check if successful
1719481Snilay@cs.wisc.edu        if (!success)  {
17210798Ssteve.reinhardt@amd.com            // inhibited packets should never be forced to retry
1739481Snilay@cs.wisc.edu            assert(!pkt->memInhibitAsserted());
1749481Snilay@cs.wisc.edu
1759481Snilay@cs.wisc.edu            // if it was added as outstanding and the send failed, then
1769481Snilay@cs.wisc.edu            // erase it again
1779481Snilay@cs.wisc.edu            if (add_outstanding)
1789988Snilay@cs.wisc.edu                outstandingReq.erase(pkt->req);
1799481Snilay@cs.wisc.edu
1809481Snilay@cs.wisc.edu            DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n",
18111570SCurtis.Dunham@arm.com                    src_port->name(), pkt->cmdString(), pkt->getAddr());
18211570SCurtis.Dunham@arm.com
18311570SCurtis.Dunham@arm.com            // update the bus state and schedule an idle event
18411570SCurtis.Dunham@arm.com            reqLayer.failedTiming(src_port, headerFinishTime);
18511570SCurtis.Dunham@arm.com        } else {
18611570SCurtis.Dunham@arm.com            // update the bus state and schedule an idle event
1879481Snilay@cs.wisc.edu            reqLayer.succeededTiming(packetFinishTime);
1889481Snilay@cs.wisc.edu        }
1899481Snilay@cs.wisc.edu    }
1909481Snilay@cs.wisc.edu
1919481Snilay@cs.wisc.edu    return success;
19211570SCurtis.Dunham@arm.com}
1939481Snilay@cs.wisc.edu
1945703SN/Abool
19511103Snilay@cs.wisc.eduCoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id)
1969885Sstever@gmail.com{
19711680SCurtis.Dunham@arm.com    // determine the source port based on the id
1985703SN/A    MasterPort *src_port = masterPorts[master_port_id];
1999885Sstever@gmail.com
20011245Sandreas.sandberg@arm.com    // test if the bus should be considered occupied for the current
20111570SCurtis.Dunham@arm.com    // port
20210798Ssteve.reinhardt@amd.com    if (!respLayer.tryTiming(src_port)) {
2039988Snilay@cs.wisc.edu        DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n",
2049348SAli.Saidi@ARM.com                src_port->name(), pkt->cmdString(), pkt->getAddr());
20510900Snilay@cs.wisc.edu        return false;
2065703SN/A    }
2075703SN/A
20811570SCurtis.Dunham@arm.com    DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x\n",
20911570SCurtis.Dunham@arm.com            src_port->name(), pkt->cmdString(), pkt->getAddr());
21011570SCurtis.Dunham@arm.com
21111570SCurtis.Dunham@arm.com    calcPacketTiming(pkt);
2125876SN/A    Tick packetFinishTime = pkt->finishTime;
2138835SAli.Saidi@ARM.com
2149348SAli.Saidi@ARM.com    // the packet is a normal response to a request that we should
21510036SAli.Saidi@ARM.com    // have seen passing through the bus
2165703SN/A    assert(outstandingReq.find(pkt->req) != outstandingReq.end());
2178835SAli.Saidi@ARM.com
2189885Sstever@gmail.com    // remove it as outstanding
2195703SN/A    outstandingReq.erase(pkt->req);
2205703SN/A
22111245Sandreas.sandberg@arm.com    // send the packet to the destination through one of our slave
2225703SN/A    // ports, as determined by the destination field
2238983Snate@binkert.org    bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTimingResp(pkt);
2245703SN/A
2259885Sstever@gmail.com    // currently it is illegal to block responses... can lead to
2269885Sstever@gmail.com    // deadlock
2279885Sstever@gmail.com    assert(success);
2289885Sstever@gmail.com
2299885Sstever@gmail.com    respLayer.succeededTiming(packetFinishTime);
23011570SCurtis.Dunham@arm.com
2319988Snilay@cs.wisc.edu    return true;
2329885Sstever@gmail.com}
23311570SCurtis.Dunham@arm.com
23411570SCurtis.Dunham@arm.comvoid
23511570SCurtis.Dunham@arm.comCoherentBus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id)
23611570SCurtis.Dunham@arm.com{
23710036SAli.Saidi@ARM.com    DPRINTF(CoherentBus, "recvTimingSnoopReq: src %s %s 0x%x\n",
2389885Sstever@gmail.com            masterPorts[master_port_id]->name(), pkt->cmdString(),
2399885Sstever@gmail.com            pkt->getAddr());
2405703SN/A
2416024SN/A    // we should only see express snoops from caches
2429988Snilay@cs.wisc.edu    assert(pkt->isExpressSnoop());
2435703SN/A
2445703SN/A    // set the source port for routing of the response
2455703SN/A    pkt->setSrc(master_port_id);
2465703SN/A
2477761SN/A    // forward to all snoopers
2487761SN/A    forwardTiming(pkt, InvalidPortID);
2499988Snilay@cs.wisc.edu
2505703SN/A    // a snoop request came from a connected slave device (one of
2515703SN/A    // our master ports), and if it is not coming from the slave
2525703SN/A    // device responsible for the address range something is
2535703SN/A    // wrong, hence there is nothing further to do as the packet
2545703SN/A    // would be going back to where it came from
2559988Snilay@cs.wisc.edu    assert(master_port_id == findPort(pkt->getAddr()));
2565703SN/A}
2575703SN/A
2585703SN/Abool
2595703SN/ACoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id)
2609988Snilay@cs.wisc.edu{
2615703SN/A    // determine the source port based on the id
2625703SN/A    SlavePort* src_port = slavePorts[slave_port_id];
26310900Snilay@cs.wisc.edu
2645703SN/A    // test if the bus should be considered occupied for the current
2655703SN/A    // port
2665703SN/A    if (!snoopRespLayer.tryTiming(src_port)) {
2675703SN/A        DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n",
2685703SN/A                src_port->name(), pkt->cmdString(), pkt->getAddr());
2699988Snilay@cs.wisc.edu        return false;
2705703SN/A    }
2715703SN/A
2725703SN/A    DPRINTF(CoherentBus, "recvTimingSnoop: src %s %s 0x%x\n",
2735703SN/A            src_port->name(), pkt->cmdString(), pkt->getAddr());
2749988Snilay@cs.wisc.edu
2755703SN/A    // get the destination from the packet
2765703SN/A    PortID dest = pkt->getDest();
27710900Snilay@cs.wisc.edu
2785703SN/A    // responses are never express snoops
2795703SN/A    assert(!pkt->isExpressSnoop());
2805703SN/A
2819988Snilay@cs.wisc.edu    calcPacketTiming(pkt);
2825703SN/A    Tick packetFinishTime = pkt->finishTime;
2835703SN/A
28410900Snilay@cs.wisc.edu    // determine if the response is from a snoop request we
2855703SN/A    // created as the result of a normal request (in which case it
2865703SN/A    // should be in the outstandingReq), or if we merely forwarded
2875703SN/A    // someone else's snoop request
2885703SN/A    if (outstandingReq.find(pkt->req) == outstandingReq.end()) {
2895703SN/A        // this is a snoop response to a snoop request we
2909988Snilay@cs.wisc.edu        // forwarded, e.g. coming from the L1 and going to the L2
2915703SN/A        // this should be forwarded as a snoop response
2925703SN/A        bool success M5_VAR_USED = masterPorts[dest]->sendTimingSnoopResp(pkt);
2935703SN/A        assert(success);
2945703SN/A    } else {
2959988Snilay@cs.wisc.edu        // we got a snoop response on one of our slave ports,
2965703SN/A        // i.e. from a coherent master connected to the bus, and
2975703SN/A        // since we created the snoop request as part of
29810900Snilay@cs.wisc.edu        // recvTiming, this should now be a normal response again
2995703SN/A        outstandingReq.erase(pkt->req);
3005703SN/A
3015703SN/A        // this is a snoop response from a coherent master, with a
3029988Snilay@cs.wisc.edu        // destination field set on its way through the bus as
3035703SN/A        // request, hence it should never go back to where the
3045703SN/A        // snoop response came from, but instead to where the
30510900Snilay@cs.wisc.edu        // original request came from
3065703SN/A        assert(slave_port_id != dest);
3075703SN/A
3085703SN/A        // as a normal response, it should go back to a master
3099988Snilay@cs.wisc.edu        // through one of our slave ports
3105703SN/A        bool success M5_VAR_USED = slavePorts[dest]->sendTimingResp(pkt);
3115703SN/A
31210900Snilay@cs.wisc.edu        // currently it is illegal to block responses... can lead
3135703SN/A        // to deadlock
3145703SN/A        assert(success);
3155703SN/A    }
3165703SN/A
3175703SN/A    snoopRespLayer.succeededTiming(packetFinishTime);
3189988Snilay@cs.wisc.edu
3195703SN/A    return true;
3205703SN/A}
3215703SN/A
3225703SN/A
3239988Snilay@cs.wisc.eduvoid
3245703SN/ACoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id)
3255703SN/A{
32610900Snilay@cs.wisc.edu    for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
3275703SN/A        SlavePort *p = *s;
3285703SN/A        // we could have gotten this request from a snooping master
3295703SN/A        // (corresponding to our own slave port that is also in
3309988Snilay@cs.wisc.edu        // snoopPorts) and should not send it back to where it came
3315703SN/A        // from
3325703SN/A        if (exclude_slave_port_id == InvalidPortID ||
33310900Snilay@cs.wisc.edu            p->getId() != exclude_slave_port_id) {
3345703SN/A            // cache is not allowed to refuse snoop
3355703SN/A            p->sendTimingSnoopReq(pkt);
3365703SN/A        }
3379988Snilay@cs.wisc.edu    }
3385703SN/A}
3395703SN/A
34010900Snilay@cs.wisc.eduvoid
3415703SN/ACoherentBus::recvRetry()
3425703SN/A{
3435703SN/A    // responses and snoop responses never block on forwarding them,
3445703SN/A    // so the retry will always be coming from a port to which we
3455703SN/A    // tried to forward a request
3469988Snilay@cs.wisc.edu    reqLayer.recvRetry();
3475703SN/A}
3485703SN/A
3495703SN/ATick
3505703SN/ACoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id)
3519988Snilay@cs.wisc.edu{
3525703SN/A    DPRINTF(CoherentBus, "recvAtomic: packet src %s addr 0x%x cmd %s\n",
3535703SN/A            slavePorts[slave_port_id]->name(), pkt->getAddr(),
35410900Snilay@cs.wisc.edu            pkt->cmdString());
3555703SN/A
3565703SN/A    MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
3575703SN/A    Tick snoop_response_latency = 0;
3587761SN/A
3597761SN/A    // uncacheable requests need never be snooped
3609988Snilay@cs.wisc.edu    if (!pkt->req->isUncacheable()) {
3617761SN/A        // forward to all snoopers but the source
3625703SN/A        std::pair<MemCmd, Tick> snoop_result =
3637761SN/A            forwardAtomic(pkt, slave_port_id);
3645703SN/A        snoop_response_cmd = snoop_result.first;
3659988Snilay@cs.wisc.edu        snoop_response_latency = snoop_result.second;
3667761SN/A    }
3677761SN/A
36810900Snilay@cs.wisc.edu    // even if we had a snoop response, we must continue and also
3697761SN/A    // perform the actual request at the destination
3707761SN/A    PortID dest_id = findPort(pkt->getAddr());
3717761SN/A
3729988Snilay@cs.wisc.edu    // forward the request to the appropriate destination
3737761SN/A    Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt);
3747761SN/A
37510900Snilay@cs.wisc.edu    // if we got a response from a snooper, restore it here
3767761SN/A    if (snoop_response_cmd != MemCmd::InvalidCmd) {
3777761SN/A        // no one else should have responded
3787761SN/A        assert(!pkt->isResponse());
3799988Snilay@cs.wisc.edu        pkt->cmd = snoop_response_cmd;
3807761SN/A        response_latency = snoop_response_latency;
3817761SN/A    }
38210900Snilay@cs.wisc.edu
3837761SN/A    pkt->finishTime = curTick() + response_latency;
3847761SN/A    return response_latency;
3857761SN/A}
3869988Snilay@cs.wisc.edu
3877761SN/ATick
3887761SN/ACoherentBus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id)
38910900Snilay@cs.wisc.edu{
3907761SN/A    DPRINTF(CoherentBus, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n",
3917761SN/A            masterPorts[master_port_id]->name(), pkt->getAddr(),
3927761SN/A            pkt->cmdString());
3939988Snilay@cs.wisc.edu
3947761SN/A    // forward to all snoopers
3957761SN/A    std::pair<MemCmd, Tick> snoop_result =
39610900Snilay@cs.wisc.edu        forwardAtomic(pkt, InvalidPortID);
3977761SN/A    MemCmd snoop_response_cmd = snoop_result.first;
3987761SN/A    Tick snoop_response_latency = snoop_result.second;
3997761SN/A
4009988Snilay@cs.wisc.edu    if (snoop_response_cmd != MemCmd::InvalidCmd)
4017761SN/A        pkt->cmd = snoop_response_cmd;
4027761SN/A
40310900Snilay@cs.wisc.edu    pkt->finishTime = curTick() + snoop_response_latency;
4047761SN/A    return snoop_response_latency;
4057761SN/A}
4067761SN/A
4079988Snilay@cs.wisc.edustd::pair<MemCmd, Tick>
4087761SN/ACoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id)
4097761SN/A{
41010900Snilay@cs.wisc.edu    // the packet may be changed on snoops, record the original
4117761SN/A    // command to enable us to restore it between snoops so that
4127761SN/A    // additional snoops can take place properly
4137761SN/A    MemCmd orig_cmd = pkt->cmd;
4149988Snilay@cs.wisc.edu    MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
4157761SN/A    Tick snoop_response_latency = 0;
4167761SN/A
41710900Snilay@cs.wisc.edu    for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
4187761SN/A        SlavePort *p = *s;
4197761SN/A        // we could have gotten this request from a snooping master
4207761SN/A        // (corresponding to our own slave port that is also in
4219988Snilay@cs.wisc.edu        // snoopPorts) and should not send it back to where it came
4227761SN/A        // from
4237761SN/A        if (exclude_slave_port_id == InvalidPortID ||
42410900Snilay@cs.wisc.edu            p->getId() != exclude_slave_port_id) {
4257761SN/A            Tick latency = p->sendAtomicSnoop(pkt);
4267761SN/A            // in contrast to a functional access, we have to keep on
4277761SN/A            // going as all snoopers must be updated even if we get a
4289988Snilay@cs.wisc.edu            // response
4297761SN/A            if (pkt->isResponse()) {
4307761SN/A                // response from snoop agent
43110900Snilay@cs.wisc.edu                assert(pkt->cmd != orig_cmd);
4327761SN/A                assert(pkt->memInhibitAsserted());
4337761SN/A                // should only happen once
4347761SN/A                assert(snoop_response_cmd == MemCmd::InvalidCmd);
4359988Snilay@cs.wisc.edu                // save response state
4367761SN/A                snoop_response_cmd = pkt->cmd;
4377761SN/A                snoop_response_latency = latency;
43810900Snilay@cs.wisc.edu                // restore original packet state for remaining snoopers
4397761SN/A                pkt->cmd = orig_cmd;
4407761SN/A            }
4417761SN/A        }
4429988Snilay@cs.wisc.edu    }
4437761SN/A
4447761SN/A    // the packet is restored as part of the loop and any potential
44510900Snilay@cs.wisc.edu    // snoop response is part of the returned pair
4467761SN/A    return std::make_pair(snoop_response_cmd, snoop_response_latency);
4477761SN/A}
4487761SN/A
4499988Snilay@cs.wisc.eduvoid
4507761SN/ACoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id)
4517761SN/A{
45210900Snilay@cs.wisc.edu    if (!pkt->isPrint()) {
4537761SN/A        // don't do DPRINTFs on PrintReq as it clutters up the output
4547761SN/A        DPRINTF(CoherentBus,
4557761SN/A                "recvFunctional: packet src %s addr 0x%x cmd %s\n",
4569988Snilay@cs.wisc.edu                slavePorts[slave_port_id]->name(), pkt->getAddr(),
4577761SN/A                pkt->cmdString());
4587761SN/A    }
45910900Snilay@cs.wisc.edu
4607761SN/A    // uncacheable requests need never be snooped
4617761SN/A    if (!pkt->req->isUncacheable()) {
4627761SN/A        // forward to all snoopers but the source
4639988Snilay@cs.wisc.edu        forwardFunctional(pkt, slave_port_id);
4647761SN/A    }
4657761SN/A
46610900Snilay@cs.wisc.edu    // there is no need to continue if the snooping has found what we
4677761SN/A    // were looking for and the packet is already a response
4687761SN/A    if (!pkt->isResponse()) {
4697761SN/A        PortID dest_id = findPort(pkt->getAddr());
4709988Snilay@cs.wisc.edu
4717761SN/A        masterPorts[dest_id]->sendFunctional(pkt);
4727761SN/A    }
47310900Snilay@cs.wisc.edu}
4747761SN/A
4757761SN/Avoid
4767761SN/ACoherentBus::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id)
4779988Snilay@cs.wisc.edu{
4787761SN/A    if (!pkt->isPrint()) {
4797761SN/A        // don't do DPRINTFs on PrintReq as it clutters up the output
48010900Snilay@cs.wisc.edu        DPRINTF(CoherentBus,
4817761SN/A                "recvFunctionalSnoop: packet src %s addr 0x%x cmd %s\n",
4827761SN/A                masterPorts[master_port_id]->name(), pkt->getAddr(),
4837761SN/A                pkt->cmdString());
4849988Snilay@cs.wisc.edu    }
4857761SN/A
4867761SN/A    // forward to all snoopers
48710900Snilay@cs.wisc.edu    forwardFunctional(pkt, InvalidPortID);
4887761SN/A}
4897761SN/A
4907761SN/Avoid
4919988Snilay@cs.wisc.eduCoherentBus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id)
4927761SN/A{
4937761SN/A    for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
49410900Snilay@cs.wisc.edu        SlavePort *p = *s;
4957761SN/A        // we could have gotten this request from a snooping master
4967761SN/A        // (corresponding to our own slave port that is also in
4977761SN/A        // snoopPorts) and should not send it back to where it came
4989988Snilay@cs.wisc.edu        // from
4997761SN/A        if (exclude_slave_port_id == InvalidPortID ||
5005703SN/A            p->getId() != exclude_slave_port_id)
50110900Snilay@cs.wisc.edu            p->sendFunctionalSnoop(pkt);
5025703SN/A
5035703SN/A        // if we get a response we are done
5045703SN/A        if (pkt->isResponse()) {
5057761SN/A            break;
5067761SN/A        }
5079988Snilay@cs.wisc.edu    }
5087761SN/A}
5095703SN/A
5107761SN/Aunsigned int
5115703SN/ACoherentBus::drain(Event *de)
5129988Snilay@cs.wisc.edu{
5135703SN/A    // sum up the individual layers
5145703SN/A    return reqLayer.drain(de) + respLayer.drain(de) + snoopRespLayer.drain(de);
51510900Snilay@cs.wisc.edu}
5165703SN/A
5175703SN/ACoherentBus *
5185703SN/ACoherentBusParams::create()
5197761SN/A{
5207761SN/A    return new CoherentBus(this);
5219988Snilay@cs.wisc.edu}
5227761SN/A