coherent_xbar.cc revision 9092
112855Sgabeblack@google.com/*
213490Sgabeblack@google.com * Copyright (c) 2011-2012 ARM Limited
312855Sgabeblack@google.com * All rights reserved
413490Sgabeblack@google.com *
512855Sgabeblack@google.com * The license below extends only to copyright in the software and shall
613490Sgabeblack@google.com * not be construed as granting a license to any other intellectual
712855Sgabeblack@google.com * property including but not limited to intellectual property relating
813490Sgabeblack@google.com * to a hardware implementation of the functionality of the software
912855Sgabeblack@google.com * licensed hereunder.  You may use the software subject to the license
1013490Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated
1112855Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software,
1213490Sgabeblack@google.com * modified or unmodified, in source code or in binary form.
1312855Sgabeblack@google.com *
1413490Sgabeblack@google.com * Copyright (c) 2006 The Regents of The University of Michigan
1512855Sgabeblack@google.com * All rights reserved.
1613490Sgabeblack@google.com *
1712855Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
1813490Sgabeblack@google.com * modification, are permitted provided that the following conditions are
1912855Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
2013490Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
2112855Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
2213490Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
2312855Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
2413490Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
2512855Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
2613490Sgabeblack@google.com * this software without specific prior written permission.
2712855Sgabeblack@google.com *
2813490Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2912855Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3013490Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3112855Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3213490Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3312855Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3413490Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3512855Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3613490Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3712855Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3813490Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3912855Sgabeblack@google.com *
4013490Sgabeblack@google.com * Authors: Ali Saidi
4112855Sgabeblack@google.com *          Andreas Hansson
4213490Sgabeblack@google.com *          William Wang
4312855Sgabeblack@google.com */
4413490Sgabeblack@google.com
4512855Sgabeblack@google.com/**
4613490Sgabeblack@google.com * @file
4712855Sgabeblack@google.com * Definition of a bus object.
4813490Sgabeblack@google.com */
4912855Sgabeblack@google.com
5013490Sgabeblack@google.com#include "base/misc.hh"
5112855Sgabeblack@google.com#include "base/trace.hh"
5213490Sgabeblack@google.com#include "debug/BusAddrRanges.hh"
5312855Sgabeblack@google.com#include "debug/CoherentBus.hh"
5413490Sgabeblack@google.com#include "mem/coherent_bus.hh"
5512855Sgabeblack@google.com
5613490Sgabeblack@google.comCoherentBus::CoherentBus(const CoherentBusParams *p)
5712855Sgabeblack@google.com    : BaseBus(p), layer(*this, ".layer", p->clock)
5813490Sgabeblack@google.com{
5912855Sgabeblack@google.com    // create the ports based on the size of the master and slave
6013490Sgabeblack@google.com    // vector ports, and the presence of the default port, the ports
6112855Sgabeblack@google.com    // are enumerated starting from zero
6213490Sgabeblack@google.com    for (int i = 0; i < p->port_master_connection_count; ++i) {
6312855Sgabeblack@google.com        std::string portName = csprintf("%s-p%d", name(), i);
6413490Sgabeblack@google.com        MasterPort* bp = new CoherentBusMasterPort(portName, *this, i);
6512855Sgabeblack@google.com        masterPorts.push_back(bp);
6613490Sgabeblack@google.com    }
6712855Sgabeblack@google.com
6813490Sgabeblack@google.com    // see if we have a default slave device connected and if so add
6912855Sgabeblack@google.com    // our corresponding master port
7013490Sgabeblack@google.com    if (p->port_default_connection_count) {
7112855Sgabeblack@google.com        defaultPortID = masterPorts.size();
7213490Sgabeblack@google.com        std::string portName = csprintf("%s-default", name());
7312855Sgabeblack@google.com        MasterPort* bp = new CoherentBusMasterPort(portName, *this,
7413490Sgabeblack@google.com                                                   defaultPortID);
7512855Sgabeblack@google.com        masterPorts.push_back(bp);
7613490Sgabeblack@google.com    }
7712855Sgabeblack@google.com
7813490Sgabeblack@google.com    // create the slave ports, once again starting at zero
7912855Sgabeblack@google.com    for (int i = 0; i < p->port_slave_connection_count; ++i) {
8013490Sgabeblack@google.com        std::string portName = csprintf("%s-p%d", name(), i);
8112855Sgabeblack@google.com        SlavePort* bp = new CoherentBusSlavePort(portName, *this, i);
8213490Sgabeblack@google.com        slavePorts.push_back(bp);
8312855Sgabeblack@google.com    }
8413490Sgabeblack@google.com
8512855Sgabeblack@google.com    clearPortCache();
8613490Sgabeblack@google.com}
8712855Sgabeblack@google.com
8813490Sgabeblack@google.comvoid
8912855Sgabeblack@google.comCoherentBus::init()
9013490Sgabeblack@google.com{
9112855Sgabeblack@google.com    // iterate over our slave ports and determine which of our
9213490Sgabeblack@google.com    // neighbouring master ports are snooping and add them as snoopers
9312855Sgabeblack@google.com    for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end();
9413490Sgabeblack@google.com         ++p) {
9512855Sgabeblack@google.com        // check if the connected master port is snooping
9613490Sgabeblack@google.com        if ((*p)->isSnooping()) {
9712855Sgabeblack@google.com            DPRINTF(BusAddrRanges, "Adding snooping master %s\n",
9813490Sgabeblack@google.com                    (*p)->getMasterPort().name());
9912855Sgabeblack@google.com            snoopPorts.push_back(*p);
10013490Sgabeblack@google.com        }
10112855Sgabeblack@google.com    }
10213490Sgabeblack@google.com
10312855Sgabeblack@google.com    if (snoopPorts.empty())
10413490Sgabeblack@google.com        warn("CoherentBus %s has no snooping ports attached!\n", name());
10512855Sgabeblack@google.com}
10613490Sgabeblack@google.com
10712855Sgabeblack@google.combool
10813490Sgabeblack@google.comCoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
10912855Sgabeblack@google.com{
11013490Sgabeblack@google.com    // determine the source port based on the id
11112855Sgabeblack@google.com    SlavePort *src_port = slavePorts[slave_port_id];
11213490Sgabeblack@google.com
11312855Sgabeblack@google.com    // remember if the packet is an express snoop
11413490Sgabeblack@google.com    bool is_express_snoop = pkt->isExpressSnoop();
11512855Sgabeblack@google.com
11613490Sgabeblack@google.com    // test if the bus should be considered occupied for the current
11712855Sgabeblack@google.com    // port, and exclude express snoops from the check
11813490Sgabeblack@google.com    if (!is_express_snoop && !layer.tryTiming(src_port)) {
11912855Sgabeblack@google.com        DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x BUSY\n",
12013490Sgabeblack@google.com                src_port->name(), pkt->cmdString(), pkt->getAddr());
12112855Sgabeblack@google.com        return false;
12213490Sgabeblack@google.com    }
12312855Sgabeblack@google.com
12413490Sgabeblack@google.com    DPRINTF(CoherentBus, "recvTimingReq: src %s %s expr %d 0x%x\n",
12512855Sgabeblack@google.com            src_port->name(), pkt->cmdString(), is_express_snoop,
12613490Sgabeblack@google.com            pkt->getAddr());
12712855Sgabeblack@google.com
12813490Sgabeblack@google.com    // set the source port for routing of the response
12912855Sgabeblack@google.com    pkt->setSrc(slave_port_id);
13013490Sgabeblack@google.com
13112855Sgabeblack@google.com    Tick headerFinishTime = is_express_snoop ? 0 : calcPacketTiming(pkt);
13213490Sgabeblack@google.com    Tick packetFinishTime = is_express_snoop ? 0 : pkt->finishTime;
13312855Sgabeblack@google.com
13413490Sgabeblack@google.com    // uncacheable requests need never be snooped
13512855Sgabeblack@google.com    if (!pkt->req->isUncacheable()) {
13613490Sgabeblack@google.com        // the packet is a memory-mapped request and should be
13712855Sgabeblack@google.com        // broadcasted to our snoopers but the source
13813490Sgabeblack@google.com        forwardTiming(pkt, slave_port_id);
13912855Sgabeblack@google.com    }
14013490Sgabeblack@google.com
14112855Sgabeblack@google.com    // remember if we add an outstanding req so we can undo it if
14213490Sgabeblack@google.com    // necessary, if the packet needs a response, we should add it
14312855Sgabeblack@google.com    // as outstanding and express snoops never fail so there is
14413490Sgabeblack@google.com    // not need to worry about them
14512855Sgabeblack@google.com    bool add_outstanding = !is_express_snoop && pkt->needsResponse();
14613490Sgabeblack@google.com
14712855Sgabeblack@google.com    // keep track that we have an outstanding request packet
14813490Sgabeblack@google.com    // matching this request, this is used by the coherency
14912855Sgabeblack@google.com    // mechanism in determining what to do with snoop responses
15013490Sgabeblack@google.com    // (in recvTimingSnoop)
15112855Sgabeblack@google.com    if (add_outstanding) {
15213490Sgabeblack@google.com        // we should never have an exsiting request outstanding
15312855Sgabeblack@google.com        assert(outstandingReq.find(pkt->req) == outstandingReq.end());
15413490Sgabeblack@google.com        outstandingReq.insert(pkt->req);
15512855Sgabeblack@google.com    }
15613490Sgabeblack@google.com
15712855Sgabeblack@google.com    // since it is a normal request, determine the destination
15813490Sgabeblack@google.com    // based on the address and attempt to send the packet
15912855Sgabeblack@google.com    bool success = masterPorts[findPort(pkt->getAddr())]->sendTimingReq(pkt);
16013490Sgabeblack@google.com
16112855Sgabeblack@google.com    // if this is an express snoop, we are done at this point
16213490Sgabeblack@google.com    if (is_express_snoop) {
16312855Sgabeblack@google.com        assert(success);
16413490Sgabeblack@google.com    } else {
16512855Sgabeblack@google.com        // for normal requests, check if successful
16613490Sgabeblack@google.com        if (!success)  {
16712855Sgabeblack@google.com            // inhibited packets should never be forced to retry
16813490Sgabeblack@google.com            assert(!pkt->memInhibitAsserted());
16912855Sgabeblack@google.com
17013490Sgabeblack@google.com            // if it was added as outstanding and the send failed, then
17112855Sgabeblack@google.com            // erase it again
17213490Sgabeblack@google.com            if (add_outstanding)
17312855Sgabeblack@google.com                outstandingReq.erase(pkt->req);
17413490Sgabeblack@google.com
17512855Sgabeblack@google.com            DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n",
17613490Sgabeblack@google.com                    src_port->name(), pkt->cmdString(), pkt->getAddr());
17712855Sgabeblack@google.com
17813490Sgabeblack@google.com            // update the bus state and schedule an idle event
17912855Sgabeblack@google.com            layer.failedTiming(src_port, headerFinishTime);
18013490Sgabeblack@google.com        } else {
18112855Sgabeblack@google.com            // update the bus state and schedule an idle event
18213490Sgabeblack@google.com            layer.succeededTiming(packetFinishTime);
18312855Sgabeblack@google.com        }
18413490Sgabeblack@google.com    }
18512855Sgabeblack@google.com
18613490Sgabeblack@google.com    return success;
18712855Sgabeblack@google.com}
18813490Sgabeblack@google.com
18912855Sgabeblack@google.combool
19013490Sgabeblack@google.comCoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id)
19112855Sgabeblack@google.com{
19213490Sgabeblack@google.com    // determine the source port based on the id
19312855Sgabeblack@google.com    MasterPort *src_port = masterPorts[master_port_id];
19413490Sgabeblack@google.com
19512855Sgabeblack@google.com    // test if the bus should be considered occupied for the current
19613490Sgabeblack@google.com    // port
19712855Sgabeblack@google.com    if (!layer.tryTiming(src_port)) {
19813490Sgabeblack@google.com        DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n",
19912855Sgabeblack@google.com                src_port->name(), pkt->cmdString(), pkt->getAddr());
20013490Sgabeblack@google.com        return false;
20112855Sgabeblack@google.com    }
20213490Sgabeblack@google.com
20312855Sgabeblack@google.com    DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x\n",
20413490Sgabeblack@google.com            src_port->name(), pkt->cmdString(), pkt->getAddr());
20512855Sgabeblack@google.com
20613490Sgabeblack@google.com    calcPacketTiming(pkt);
20712855Sgabeblack@google.com    Tick packetFinishTime = pkt->finishTime;
20813490Sgabeblack@google.com
20912855Sgabeblack@google.com    // the packet is a normal response to a request that we should
21013490Sgabeblack@google.com    // have seen passing through the bus
21112855Sgabeblack@google.com    assert(outstandingReq.find(pkt->req) != outstandingReq.end());
21213490Sgabeblack@google.com
21312855Sgabeblack@google.com    // remove it as outstanding
21413490Sgabeblack@google.com    outstandingReq.erase(pkt->req);
21512855Sgabeblack@google.com
21613490Sgabeblack@google.com    // send the packet to the destination through one of our slave
21712855Sgabeblack@google.com    // ports, as determined by the destination field
21813490Sgabeblack@google.com    bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTimingResp(pkt);
21912855Sgabeblack@google.com
22013490Sgabeblack@google.com    // currently it is illegal to block responses... can lead to
22112855Sgabeblack@google.com    // deadlock
22213490Sgabeblack@google.com    assert(success);
22312855Sgabeblack@google.com
22413490Sgabeblack@google.com    layer.succeededTiming(packetFinishTime);
22512855Sgabeblack@google.com
22613490Sgabeblack@google.com    return true;
22712855Sgabeblack@google.com}
22813490Sgabeblack@google.com
22912855Sgabeblack@google.comvoid
23013490Sgabeblack@google.comCoherentBus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id)
23112855Sgabeblack@google.com{
23213490Sgabeblack@google.com    DPRINTF(CoherentBus, "recvTimingSnoopReq: src %s %s 0x%x\n",
23312855Sgabeblack@google.com            masterPorts[master_port_id]->name(), pkt->cmdString(),
23413490Sgabeblack@google.com            pkt->getAddr());
23512855Sgabeblack@google.com
23613490Sgabeblack@google.com    // we should only see express snoops from caches
23712855Sgabeblack@google.com    assert(pkt->isExpressSnoop());
23813490Sgabeblack@google.com
23912855Sgabeblack@google.com    // set the source port for routing of the response
24013490Sgabeblack@google.com    pkt->setSrc(master_port_id);
24112855Sgabeblack@google.com
24213490Sgabeblack@google.com    // forward to all snoopers
24312855Sgabeblack@google.com    forwardTiming(pkt, InvalidPortID);
24413490Sgabeblack@google.com
24512855Sgabeblack@google.com    // a snoop request came from a connected slave device (one of
24613490Sgabeblack@google.com    // our master ports), and if it is not coming from the slave
24712855Sgabeblack@google.com    // device responsible for the address range something is
24813490Sgabeblack@google.com    // wrong, hence there is nothing further to do as the packet
24912855Sgabeblack@google.com    // would be going back to where it came from
25013490Sgabeblack@google.com    assert(master_port_id == findPort(pkt->getAddr()));
25112855Sgabeblack@google.com}
25213490Sgabeblack@google.com
25312855Sgabeblack@google.combool
25413490Sgabeblack@google.comCoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id)
25512855Sgabeblack@google.com{
25613490Sgabeblack@google.com    // determine the source port based on the id
25712855Sgabeblack@google.com    SlavePort* src_port = slavePorts[slave_port_id];
25813490Sgabeblack@google.com
25912855Sgabeblack@google.com    // test if the bus should be considered occupied for the current
26013490Sgabeblack@google.com    // port
26112855Sgabeblack@google.com    if (!layer.tryTiming(src_port)) {
26213490Sgabeblack@google.com        DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n",
26312855Sgabeblack@google.com                src_port->name(), pkt->cmdString(), pkt->getAddr());
26413490Sgabeblack@google.com        return false;
26512855Sgabeblack@google.com    }
26613490Sgabeblack@google.com
26712855Sgabeblack@google.com    DPRINTF(CoherentBus, "recvTimingSnoop: src %s %s 0x%x\n",
26813490Sgabeblack@google.com            src_port->name(), pkt->cmdString(), pkt->getAddr());
26912855Sgabeblack@google.com
27013490Sgabeblack@google.com    // get the destination from the packet
27112855Sgabeblack@google.com    PortID dest = pkt->getDest();
27213490Sgabeblack@google.com
27312855Sgabeblack@google.com    // responses are never express snoops
27413490Sgabeblack@google.com    assert(!pkt->isExpressSnoop());
27512855Sgabeblack@google.com
27613490Sgabeblack@google.com    calcPacketTiming(pkt);
27712855Sgabeblack@google.com    Tick packetFinishTime = pkt->finishTime;
27813490Sgabeblack@google.com
27912855Sgabeblack@google.com    // determine if the response is from a snoop request we
28013490Sgabeblack@google.com    // created as the result of a normal request (in which case it
28112855Sgabeblack@google.com    // should be in the outstandingReq), or if we merely forwarded
28213490Sgabeblack@google.com    // someone else's snoop request
28312855Sgabeblack@google.com    if (outstandingReq.find(pkt->req) == outstandingReq.end()) {
28413490Sgabeblack@google.com        // this is a snoop response to a snoop request we
28512855Sgabeblack@google.com        // forwarded, e.g. coming from the L1 and going to the L2
28613490Sgabeblack@google.com        // this should be forwarded as a snoop response
28712855Sgabeblack@google.com        bool success M5_VAR_USED = masterPorts[dest]->sendTimingSnoopResp(pkt);
28813490Sgabeblack@google.com        assert(success);
28912855Sgabeblack@google.com    } else {
29013490Sgabeblack@google.com        // we got a snoop response on one of our slave ports,
29112855Sgabeblack@google.com        // i.e. from a coherent master connected to the bus, and
29213490Sgabeblack@google.com        // since we created the snoop request as part of
29312855Sgabeblack@google.com        // recvTiming, this should now be a normal response again
29413490Sgabeblack@google.com        outstandingReq.erase(pkt->req);
29512855Sgabeblack@google.com
29613490Sgabeblack@google.com        // this is a snoop response from a coherent master, with a
29712855Sgabeblack@google.com        // destination field set on its way through the bus as
29813490Sgabeblack@google.com        // request, hence it should never go back to where the
29912855Sgabeblack@google.com        // snoop response came from, but instead to where the
30013490Sgabeblack@google.com        // original request came from
30112855Sgabeblack@google.com        assert(slave_port_id != dest);
30213490Sgabeblack@google.com
30312855Sgabeblack@google.com        // as a normal response, it should go back to a master
30413490Sgabeblack@google.com        // through one of our slave ports
30512855Sgabeblack@google.com        bool success M5_VAR_USED = slavePorts[dest]->sendTimingResp(pkt);
30613490Sgabeblack@google.com
30712855Sgabeblack@google.com        // currently it is illegal to block responses... can lead
30813490Sgabeblack@google.com        // to deadlock
30912855Sgabeblack@google.com        assert(success);
31013490Sgabeblack@google.com    }
31112855Sgabeblack@google.com
31213490Sgabeblack@google.com    layer.succeededTiming(packetFinishTime);
31312855Sgabeblack@google.com
31413490Sgabeblack@google.com    return true;
31512855Sgabeblack@google.com}
31613490Sgabeblack@google.com
31712855Sgabeblack@google.com
31813490Sgabeblack@google.comvoid
31912855Sgabeblack@google.comCoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id)
32013490Sgabeblack@google.com{
32112855Sgabeblack@google.com    for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
32213490Sgabeblack@google.com        SlavePort *p = *s;
32312855Sgabeblack@google.com        // we could have gotten this request from a snooping master
32413490Sgabeblack@google.com        // (corresponding to our own slave port that is also in
32512855Sgabeblack@google.com        // snoopPorts) and should not send it back to where it came
32613490Sgabeblack@google.com        // from
32712855Sgabeblack@google.com        if (exclude_slave_port_id == InvalidPortID ||
32813490Sgabeblack@google.com            p->getId() != exclude_slave_port_id) {
32912855Sgabeblack@google.com            // cache is not allowed to refuse snoop
33013490Sgabeblack@google.com            p->sendTimingSnoopReq(pkt);
33112855Sgabeblack@google.com        }
33213490Sgabeblack@google.com    }
33312855Sgabeblack@google.com}
33413490Sgabeblack@google.com
33512855Sgabeblack@google.comvoid
33613490Sgabeblack@google.comCoherentBus::recvRetry()
33712855Sgabeblack@google.com{
33813490Sgabeblack@google.com    // only one layer that can deal with it
33912855Sgabeblack@google.com    layer.recvRetry();
34013490Sgabeblack@google.com}
34112855Sgabeblack@google.com
34213490Sgabeblack@google.comTick
34312855Sgabeblack@google.comCoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id)
34413490Sgabeblack@google.com{
34512855Sgabeblack@google.com    DPRINTF(CoherentBus, "recvAtomic: packet src %s addr 0x%x cmd %s\n",
34613490Sgabeblack@google.com            slavePorts[slave_port_id]->name(), pkt->getAddr(),
34712855Sgabeblack@google.com            pkt->cmdString());
34813490Sgabeblack@google.com
34912855Sgabeblack@google.com    MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
35013490Sgabeblack@google.com    Tick snoop_response_latency = 0;
35112855Sgabeblack@google.com
35213490Sgabeblack@google.com    // uncacheable requests need never be snooped
35312855Sgabeblack@google.com    if (!pkt->req->isUncacheable()) {
35413490Sgabeblack@google.com        // forward to all snoopers but the source
35512855Sgabeblack@google.com        std::pair<MemCmd, Tick> snoop_result =
35613490Sgabeblack@google.com            forwardAtomic(pkt, slave_port_id);
35712855Sgabeblack@google.com        snoop_response_cmd = snoop_result.first;
35813490Sgabeblack@google.com        snoop_response_latency = snoop_result.second;
35912855Sgabeblack@google.com    }
36013490Sgabeblack@google.com
36112855Sgabeblack@google.com    // even if we had a snoop response, we must continue and also
36213490Sgabeblack@google.com    // perform the actual request at the destination
36312855Sgabeblack@google.com    PortID dest_id = findPort(pkt->getAddr());
36413490Sgabeblack@google.com
36512855Sgabeblack@google.com    // forward the request to the appropriate destination
36613490Sgabeblack@google.com    Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt);
36712855Sgabeblack@google.com
36813490Sgabeblack@google.com    // if we got a response from a snooper, restore it here
36912855Sgabeblack@google.com    if (snoop_response_cmd != MemCmd::InvalidCmd) {
37013490Sgabeblack@google.com        // no one else should have responded
37112855Sgabeblack@google.com        assert(!pkt->isResponse());
37213490Sgabeblack@google.com        pkt->cmd = snoop_response_cmd;
37312855Sgabeblack@google.com        response_latency = snoop_response_latency;
37413490Sgabeblack@google.com    }
37512855Sgabeblack@google.com
37613490Sgabeblack@google.com    pkt->finishTime = curTick() + response_latency;
37712855Sgabeblack@google.com    return response_latency;
37813490Sgabeblack@google.com}
37912855Sgabeblack@google.com
38013490Sgabeblack@google.comTick
38112855Sgabeblack@google.comCoherentBus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id)
38213490Sgabeblack@google.com{
38312855Sgabeblack@google.com    DPRINTF(CoherentBus, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n",
38413490Sgabeblack@google.com            masterPorts[master_port_id]->name(), pkt->getAddr(),
38512855Sgabeblack@google.com            pkt->cmdString());
38613490Sgabeblack@google.com
38712855Sgabeblack@google.com    // forward to all snoopers
38813490Sgabeblack@google.com    std::pair<MemCmd, Tick> snoop_result =
38912855Sgabeblack@google.com        forwardAtomic(pkt, InvalidPortID);
39013490Sgabeblack@google.com    MemCmd snoop_response_cmd = snoop_result.first;
39112855Sgabeblack@google.com    Tick snoop_response_latency = snoop_result.second;
39213490Sgabeblack@google.com
39312855Sgabeblack@google.com    if (snoop_response_cmd != MemCmd::InvalidCmd)
39413490Sgabeblack@google.com        pkt->cmd = snoop_response_cmd;
39512855Sgabeblack@google.com
39613490Sgabeblack@google.com    pkt->finishTime = curTick() + snoop_response_latency;
39712855Sgabeblack@google.com    return snoop_response_latency;
39813490Sgabeblack@google.com}
39912855Sgabeblack@google.com
40013490Sgabeblack@google.comstd::pair<MemCmd, Tick>
40112855Sgabeblack@google.comCoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id)
40213490Sgabeblack@google.com{
40312855Sgabeblack@google.com    // the packet may be changed on snoops, record the original
40413490Sgabeblack@google.com    // command to enable us to restore it between snoops so that
40512855Sgabeblack@google.com    // additional snoops can take place properly
40613490Sgabeblack@google.com    MemCmd orig_cmd = pkt->cmd;
40712855Sgabeblack@google.com    MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
40813490Sgabeblack@google.com    Tick snoop_response_latency = 0;
40912855Sgabeblack@google.com
41013490Sgabeblack@google.com    for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
41112855Sgabeblack@google.com        SlavePort *p = *s;
41213490Sgabeblack@google.com        // we could have gotten this request from a snooping master
41312855Sgabeblack@google.com        // (corresponding to our own slave port that is also in
41413490Sgabeblack@google.com        // snoopPorts) and should not send it back to where it came
41512855Sgabeblack@google.com        // from
41613490Sgabeblack@google.com        if (exclude_slave_port_id == InvalidPortID ||
41712855Sgabeblack@google.com            p->getId() != exclude_slave_port_id) {
41813490Sgabeblack@google.com            Tick latency = p->sendAtomicSnoop(pkt);
41912855Sgabeblack@google.com            // in contrast to a functional access, we have to keep on
42013490Sgabeblack@google.com            // going as all snoopers must be updated even if we get a
42112855Sgabeblack@google.com            // response
42213490Sgabeblack@google.com            if (pkt->isResponse()) {
42312855Sgabeblack@google.com                // response from snoop agent
42413490Sgabeblack@google.com                assert(pkt->cmd != orig_cmd);
42512855Sgabeblack@google.com                assert(pkt->memInhibitAsserted());
42613490Sgabeblack@google.com                // should only happen once
42712855Sgabeblack@google.com                assert(snoop_response_cmd == MemCmd::InvalidCmd);
42813490Sgabeblack@google.com                // save response state
42912855Sgabeblack@google.com                snoop_response_cmd = pkt->cmd;
43013490Sgabeblack@google.com                snoop_response_latency = latency;
43112855Sgabeblack@google.com                // restore original packet state for remaining snoopers
43213490Sgabeblack@google.com                pkt->cmd = orig_cmd;
43312855Sgabeblack@google.com            }
43413490Sgabeblack@google.com        }
43512855Sgabeblack@google.com    }
43613490Sgabeblack@google.com
43712855Sgabeblack@google.com    // the packet is restored as part of the loop and any potential
43813490Sgabeblack@google.com    // snoop response is part of the returned pair
43912855Sgabeblack@google.com    return std::make_pair(snoop_response_cmd, snoop_response_latency);
44013490Sgabeblack@google.com}
44112855Sgabeblack@google.com
44213490Sgabeblack@google.comvoid
44312855Sgabeblack@google.comCoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id)
44413490Sgabeblack@google.com{
44512855Sgabeblack@google.com    if (!pkt->isPrint()) {
44613490Sgabeblack@google.com        // don't do DPRINTFs on PrintReq as it clutters up the output
44712855Sgabeblack@google.com        DPRINTF(CoherentBus,
44813490Sgabeblack@google.com                "recvFunctional: packet src %s addr 0x%x cmd %s\n",
44912855Sgabeblack@google.com                slavePorts[slave_port_id]->name(), pkt->getAddr(),
45013490Sgabeblack@google.com                pkt->cmdString());
45112855Sgabeblack@google.com    }
45213490Sgabeblack@google.com
45312855Sgabeblack@google.com    // uncacheable requests need never be snooped
45413490Sgabeblack@google.com    if (!pkt->req->isUncacheable()) {
45512855Sgabeblack@google.com        // forward to all snoopers but the source
45613490Sgabeblack@google.com        forwardFunctional(pkt, slave_port_id);
45712855Sgabeblack@google.com    }
45813490Sgabeblack@google.com
45912855Sgabeblack@google.com    // there is no need to continue if the snooping has found what we
46013490Sgabeblack@google.com    // were looking for and the packet is already a response
46112855Sgabeblack@google.com    if (!pkt->isResponse()) {
46213490Sgabeblack@google.com        PortID dest_id = findPort(pkt->getAddr());
46312855Sgabeblack@google.com
46413490Sgabeblack@google.com        masterPorts[dest_id]->sendFunctional(pkt);
46512855Sgabeblack@google.com    }
46613490Sgabeblack@google.com}
46712855Sgabeblack@google.com
46813490Sgabeblack@google.comvoid
46912855Sgabeblack@google.comCoherentBus::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id)
47013490Sgabeblack@google.com{
47112855Sgabeblack@google.com    if (!pkt->isPrint()) {
47213490Sgabeblack@google.com        // don't do DPRINTFs on PrintReq as it clutters up the output
47312855Sgabeblack@google.com        DPRINTF(CoherentBus,
47413490Sgabeblack@google.com                "recvFunctionalSnoop: packet src %s addr 0x%x cmd %s\n",
47512855Sgabeblack@google.com                masterPorts[master_port_id]->name(), pkt->getAddr(),
47613490Sgabeblack@google.com                pkt->cmdString());
47712855Sgabeblack@google.com    }
47813490Sgabeblack@google.com
47912855Sgabeblack@google.com    // forward to all snoopers
48013490Sgabeblack@google.com    forwardFunctional(pkt, InvalidPortID);
48112855Sgabeblack@google.com}
48213490Sgabeblack@google.com
48312855Sgabeblack@google.comvoid
48413490Sgabeblack@google.comCoherentBus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id)
48512855Sgabeblack@google.com{
48613490Sgabeblack@google.com    for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
48712855Sgabeblack@google.com        SlavePort *p = *s;
48813490Sgabeblack@google.com        // we could have gotten this request from a snooping master
48912855Sgabeblack@google.com        // (corresponding to our own slave port that is also in
49013490Sgabeblack@google.com        // snoopPorts) and should not send it back to where it came
49112855Sgabeblack@google.com        // from
49213490Sgabeblack@google.com        if (exclude_slave_port_id == InvalidPortID ||
49312855Sgabeblack@google.com            p->getId() != exclude_slave_port_id)
49413490Sgabeblack@google.com            p->sendFunctionalSnoop(pkt);
49512855Sgabeblack@google.com
49613490Sgabeblack@google.com        // if we get a response we are done
49712855Sgabeblack@google.com        if (pkt->isResponse()) {
49813490Sgabeblack@google.com            break;
49912855Sgabeblack@google.com        }
50013490Sgabeblack@google.com    }
50112855Sgabeblack@google.com}
50213490Sgabeblack@google.com
50312855Sgabeblack@google.comunsigned int
50413490Sgabeblack@google.comCoherentBus::drain(Event *de)
50512855Sgabeblack@google.com{
50613490Sgabeblack@google.com    // only one layer to worry about at the moment
50712855Sgabeblack@google.com    return layer.drain(de);
50813490Sgabeblack@google.com}
50912855Sgabeblack@google.com
51013490Sgabeblack@google.comCoherentBus *
51112855Sgabeblack@google.comCoherentBusParams::create()
51213490Sgabeblack@google.com{
51312855Sgabeblack@google.com    return new CoherentBus(this);
51413490Sgabeblack@google.com}
51512855Sgabeblack@google.com