coherent_xbar.cc revision 9612
12810SN/A/*
29614Srene.dejong@arm.com * Copyright (c) 2011-2012 ARM Limited
38856Sandreas.hansson@arm.com * All rights reserved
48856Sandreas.hansson@arm.com *
58856Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall
68856Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual
78856Sandreas.hansson@arm.com * property including but not limited to intellectual property relating
88856Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software
98856Sandreas.hansson@arm.com * licensed hereunder.  You may use the software subject to the license
108856Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated
118856Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software,
128856Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form.
138856Sandreas.hansson@arm.com *
142810SN/A * Copyright (c) 2006 The Regents of The University of Michigan
152810SN/A * All rights reserved.
162810SN/A *
172810SN/A * Redistribution and use in source and binary forms, with or without
182810SN/A * modification, are permitted provided that the following conditions are
192810SN/A * met: redistributions of source code must retain the above copyright
202810SN/A * notice, this list of conditions and the following disclaimer;
212810SN/A * redistributions in binary form must reproduce the above copyright
222810SN/A * notice, this list of conditions and the following disclaimer in the
232810SN/A * documentation and/or other materials provided with the distribution;
242810SN/A * neither the name of the copyright holders nor the names of its
252810SN/A * contributors may be used to endorse or promote products derived from
262810SN/A * this software without specific prior written permission.
272810SN/A *
282810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
292810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
302810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
312810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
322810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
332810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
342810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
352810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
362810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
372810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392810SN/A *
402810SN/A * Authors: Ali Saidi
412810SN/A *          Andreas Hansson
422810SN/A *          William Wang
432810SN/A */
442810SN/A
452810SN/A/**
462810SN/A * @file
472810SN/A * Definition of a bus object.
488232Snate@binkert.org */
499152Satgutier@umich.edu
509795Sandreas.hansson@arm.com#include "base/misc.hh"
519795Sandreas.hansson@arm.com#include "base/trace.hh"
5210263Satgutier@umich.edu#include "debug/BusAddrRanges.hh"
535338Sstever@gmail.com#include "debug/CoherentBus.hh"
549795Sandreas.hansson@arm.com#include "mem/coherent_bus.hh"
555338Sstever@gmail.com#include "sim/system.hh"
568786Sgblack@eecs.umich.edu
572810SN/ACoherentBus::CoherentBus(const CoherentBusParams *p)
582810SN/A    : BaseBus(p),
592810SN/A      reqLayer(*this, ".reqLayer", p->port_master_connection_count +
608856Sandreas.hansson@arm.com               p->port_default_connection_count),
618856Sandreas.hansson@arm.com      respLayer(*this, ".respLayer", p->port_slave_connection_count),
628856Sandreas.hansson@arm.com      snoopRespLayer(*this, ".snoopRespLayer",
638922Swilliam.wang@arm.com                     p->port_master_connection_count +
648914Sandreas.hansson@arm.com                     p->port_default_connection_count),
658856Sandreas.hansson@arm.com      system(p->system)
668856Sandreas.hansson@arm.com{
674475SN/A    // create the ports based on the size of the master and slave
6811053Sandreas.hansson@arm.com    // vector ports, and the presence of the default port, the ports
695034SN/A    // are enumerated starting from zero
7010360Sandreas.hansson@arm.com    for (int i = 0; i < p->port_master_connection_count; ++i) {
7111377Sandreas.hansson@arm.com        std::string portName = csprintf("%s.master[%d]", name(), i);
7211377Sandreas.hansson@arm.com        MasterPort* bp = new CoherentBusMasterPort(portName, *this, i);
7311053Sandreas.hansson@arm.com        masterPorts.push_back(bp);
7410693SMarco.Balboni@ARM.com    }
7510693SMarco.Balboni@ARM.com
7610693SMarco.Balboni@ARM.com    // see if we have a default slave device connected and if so add
779263Smrinmoy.ghosh@arm.com    // our corresponding master port
785034SN/A    if (p->port_default_connection_count) {
7911331Sandreas.hansson@arm.com        defaultPortID = masterPorts.size();
8010884Sandreas.hansson@arm.com        std::string portName = name() + ".default";
814626SN/A        MasterPort* bp = new CoherentBusMasterPort(portName, *this,
8210360Sandreas.hansson@arm.com                                                   defaultPortID);
834626SN/A        masterPorts.push_back(bp);
845034SN/A    }
858883SAli.Saidi@ARM.com
868833Sdam.sunwoo@arm.com    // create the slave ports, once again starting at zero
874458SN/A    for (int i = 0; i < p->port_slave_connection_count; ++i) {
8811377Sandreas.hansson@arm.com        std::string portName = csprintf("%s.slave[%d]", name(), i);
8911377Sandreas.hansson@arm.com        SlavePort* bp = new CoherentBusSlavePort(portName, *this, i);
9011377Sandreas.hansson@arm.com        slavePorts.push_back(bp);
9111377Sandreas.hansson@arm.com    }
9211377Sandreas.hansson@arm.com
9311377Sandreas.hansson@arm.com    clearPortCache();
9411331Sandreas.hansson@arm.com}
9511331Sandreas.hansson@arm.com
962810SN/Avoid
972810SN/ACoherentBus::init()
983013SN/A{
998856Sandreas.hansson@arm.com    // the base class is responsible for determining the block size
1002810SN/A    BaseBus::init();
1013013SN/A
10210714Sandreas.hansson@arm.com    // iterate over our slave ports and determine which of our
1032810SN/A    // neighbouring master ports are snooping and add them as snoopers
1049614Srene.dejong@arm.com    for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end();
1059614Srene.dejong@arm.com         ++p) {
1069614Srene.dejong@arm.com        // check if the connected master port is snooping
10710345SCurtis.Dunham@arm.com        if ((*p)->isSnooping()) {
10810714Sandreas.hansson@arm.com            DPRINTF(BusAddrRanges, "Adding snooping master %s\n",
10910345SCurtis.Dunham@arm.com                    (*p)->getMasterPort().name());
1109614Srene.dejong@arm.com            snoopPorts.push_back(*p);
1112810SN/A        }
1122810SN/A    }
1132810SN/A
1148856Sandreas.hansson@arm.com    if (snoopPorts.empty())
1152810SN/A        warn("CoherentBus %s has no snooping ports attached!\n", name());
1163013SN/A}
11710714Sandreas.hansson@arm.com
1183013SN/Abool
1198856Sandreas.hansson@arm.comCoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
12010714Sandreas.hansson@arm.com{
1218922Swilliam.wang@arm.com    // determine the source port based on the id
1222897SN/A    SlavePort *src_port = slavePorts[slave_port_id];
1232810SN/A
1242810SN/A    // remember if the packet is an express snoop
12510344Sandreas.hansson@arm.com    bool is_express_snoop = pkt->isExpressSnoop();
12610344Sandreas.hansson@arm.com
12710344Sandreas.hansson@arm.com    // determine the destination based on the address
12810714Sandreas.hansson@arm.com    PortID dest_port_id = findPort(pkt->getAddr());
12910344Sandreas.hansson@arm.com
13010344Sandreas.hansson@arm.com    // test if the bus should be considered occupied for the current
13110344Sandreas.hansson@arm.com    // port, and exclude express snoops from the check
13210713Sandreas.hansson@arm.com    if (!is_express_snoop && !reqLayer.tryTiming(src_port, dest_port_id)) {
13310344Sandreas.hansson@arm.com        DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x BUS BUSY\n",
1342844SN/A                src_port->name(), pkt->cmdString(), pkt->getAddr());
1352810SN/A        return false;
1362858SN/A    }
1372858SN/A
1388856Sandreas.hansson@arm.com    DPRINTF(CoherentBus, "recvTimingReq: src %s %s expr %d 0x%x\n",
1398922Swilliam.wang@arm.com            src_port->name(), pkt->cmdString(), is_express_snoop,
1408711Sandreas.hansson@arm.com            pkt->getAddr());
14111331Sandreas.hansson@arm.com
1422858SN/A    // set the source port for routing of the response
1432858SN/A    pkt->setSrc(slave_port_id);
1449294Sandreas.hansson@arm.com
1459294Sandreas.hansson@arm.com    calcPacketTiming(pkt);
1468922Swilliam.wang@arm.com    Tick packetFinishTime = pkt->busLastWordDelay + curTick();
1478922Swilliam.wang@arm.com
1488922Swilliam.wang@arm.com    // uncacheable requests need never be snooped
1498922Swilliam.wang@arm.com    if (!pkt->req->isUncacheable() && !system->bypassCaches()) {
1508922Swilliam.wang@arm.com        // the packet is a memory-mapped request and should be
1518922Swilliam.wang@arm.com        // broadcasted to our snoopers but the source
1528922Swilliam.wang@arm.com        forwardTiming(pkt, slave_port_id);
1538922Swilliam.wang@arm.com    }
1549294Sandreas.hansson@arm.com
1559294Sandreas.hansson@arm.com    // remember if we add an outstanding req so we can undo it if
1568922Swilliam.wang@arm.com    // necessary, if the packet needs a response, we should add it
1578922Swilliam.wang@arm.com    // as outstanding and express snoops never fail so there is
1588922Swilliam.wang@arm.com    // not need to worry about them
1598922Swilliam.wang@arm.com    bool add_outstanding = !is_express_snoop && pkt->needsResponse();
1608922Swilliam.wang@arm.com
1618922Swilliam.wang@arm.com    // keep track that we have an outstanding request packet
1628922Swilliam.wang@arm.com    // matching this request, this is used by the coherency
1634628SN/A    // mechanism in determining what to do with snoop responses
16410821Sandreas.hansson@arm.com    // (in recvTimingSnoop)
16510821Sandreas.hansson@arm.com    if (add_outstanding) {
16610821Sandreas.hansson@arm.com        // we should never have an exsiting request outstanding
16710821Sandreas.hansson@arm.com        assert(outstandingReq.find(pkt->req) == outstandingReq.end());
16810821Sandreas.hansson@arm.com        outstandingReq.insert(pkt->req);
16910821Sandreas.hansson@arm.com    }
17010821Sandreas.hansson@arm.com
17110821Sandreas.hansson@arm.com    // since it is a normal request, attempt to send the packet
17210821Sandreas.hansson@arm.com    bool success = masterPorts[dest_port_id]->sendTimingReq(pkt);
17310821Sandreas.hansson@arm.com
17410821Sandreas.hansson@arm.com    // if this is an express snoop, we are done at this point
1752858SN/A    if (is_express_snoop) {
1762810SN/A        assert(success);
1772810SN/A    } else {
1782810SN/A        // for normal requests, check if successful
1792810SN/A        if (!success)  {
1802810SN/A            // inhibited packets should never be forced to retry
1814022SN/A            assert(!pkt->memInhibitAsserted());
1824022SN/A
1834022SN/A            // if it was added as outstanding and the send failed, then
1842810SN/A            // erase it again
1852810SN/A            if (add_outstanding)
1868833Sdam.sunwoo@arm.com                outstandingReq.erase(pkt->req);
1872810SN/A
1882810SN/A            // undo the calculation so we can check for 0 again
1892810SN/A            pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
1902810SN/A
1918833Sdam.sunwoo@arm.com            DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n",
1928833Sdam.sunwoo@arm.com                    src_port->name(), pkt->cmdString(), pkt->getAddr());
1938833Sdam.sunwoo@arm.com
1942810SN/A            // update the bus state and schedule an idle event
1952810SN/A            reqLayer.failedTiming(src_port, dest_port_id,
1964871SN/A                                  clockEdge(Cycles(headerCycles)));
1974871SN/A        } else {
1984871SN/A            // update the bus state and schedule an idle event
1994871SN/A            reqLayer.succeededTiming(packetFinishTime);
20011455Sandreas.hansson@arm.com        }
20110885Sandreas.hansson@arm.com    }
2024871SN/A
2034871SN/A    return success;
2044871SN/A}
2054871SN/A
2064871SN/Abool
2072810SN/ACoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id)
2082810SN/A{
2092810SN/A    // determine the source port based on the id
2108833Sdam.sunwoo@arm.com    MasterPort *src_port = masterPorts[master_port_id];
2112810SN/A
2124871SN/A    // test if the bus should be considered occupied for the current
2138833Sdam.sunwoo@arm.com    // port
2148833Sdam.sunwoo@arm.com    if (!respLayer.tryTiming(src_port, pkt->getDest())) {
2158833Sdam.sunwoo@arm.com        DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n",
2162810SN/A                src_port->name(), pkt->cmdString(), pkt->getAddr());
2172810SN/A        return false;
2182810SN/A    }
2192810SN/A
2208833Sdam.sunwoo@arm.com    DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x\n",
2212810SN/A            src_port->name(), pkt->cmdString(), pkt->getAddr());
2224871SN/A
2238833Sdam.sunwoo@arm.com    calcPacketTiming(pkt);
2248833Sdam.sunwoo@arm.com    Tick packetFinishTime = pkt->busLastWordDelay + curTick();
2258833Sdam.sunwoo@arm.com
2262810SN/A    // the packet is a normal response to a request that we should
2272810SN/A    // have seen passing through the bus
2284022SN/A    assert(outstandingReq.find(pkt->req) != outstandingReq.end());
2294022SN/A
2304022SN/A    // remove it as outstanding
2312810SN/A    outstandingReq.erase(pkt->req);
2322810SN/A
2338833Sdam.sunwoo@arm.com    // send the packet to the destination through one of our slave
2342810SN/A    // ports, as determined by the destination field
2352810SN/A    bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTimingResp(pkt);
2362810SN/A
2372810SN/A    // currently it is illegal to block responses... can lead to
2388833Sdam.sunwoo@arm.com    // deadlock
2398833Sdam.sunwoo@arm.com    assert(success);
2408833Sdam.sunwoo@arm.com
2412810SN/A    respLayer.succeededTiming(packetFinishTime);
2422810SN/A
2432810SN/A    return true;
2442810SN/A}
2452810SN/A
2468833Sdam.sunwoo@arm.comvoid
2472810SN/ACoherentBus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id)
2484871SN/A{
2498833Sdam.sunwoo@arm.com    DPRINTF(CoherentBus, "recvTimingSnoopReq: src %s %s 0x%x\n",
2508833Sdam.sunwoo@arm.com            masterPorts[master_port_id]->name(), pkt->cmdString(),
2518833Sdam.sunwoo@arm.com            pkt->getAddr());
2522810SN/A
2532810SN/A    // we should only see express snoops from caches
2542810SN/A    assert(pkt->isExpressSnoop());
2552810SN/A
2568833Sdam.sunwoo@arm.com    // set the source port for routing of the response
2572810SN/A    pkt->setSrc(master_port_id);
2584871SN/A
2598833Sdam.sunwoo@arm.com    // forward to all snoopers
2608833Sdam.sunwoo@arm.com    forwardTiming(pkt, InvalidPortID);
2618833Sdam.sunwoo@arm.com
2622810SN/A    // a snoop request came from a connected slave device (one of
2632810SN/A    // our master ports), and if it is not coming from the slave
2644022SN/A    // device responsible for the address range something is
2654022SN/A    // wrong, hence there is nothing further to do as the packet
2664022SN/A    // would be going back to where it came from
2672810SN/A    assert(master_port_id == findPort(pkt->getAddr()));
2682810SN/A}
2698833Sdam.sunwoo@arm.com
2702810SN/Abool
2712810SN/ACoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id)
2722810SN/A{
2732810SN/A    // determine the source port based on the id
2748833Sdam.sunwoo@arm.com    SlavePort* src_port = slavePorts[slave_port_id];
2758833Sdam.sunwoo@arm.com
2768833Sdam.sunwoo@arm.com    // test if the bus should be considered occupied for the current
2772810SN/A    // port, do not use the destination port in the check as we do not
2782810SN/A    // know yet if it is to be passed on as a snoop response or normal
2792810SN/A    // response and we never block on either
2802810SN/A    if (!snoopRespLayer.tryTiming(src_port, InvalidPortID)) {
2812810SN/A        DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n",
2828833Sdam.sunwoo@arm.com                src_port->name(), pkt->cmdString(), pkt->getAddr());
2832810SN/A        return false;
2844871SN/A    }
2858833Sdam.sunwoo@arm.com
2868833Sdam.sunwoo@arm.com    DPRINTF(CoherentBus, "recvTimingSnoop: src %s %s 0x%x\n",
2878833Sdam.sunwoo@arm.com            src_port->name(), pkt->cmdString(), pkt->getAddr());
2882810SN/A
2892810SN/A    // get the destination from the packet
2902810SN/A    PortID dest = pkt->getDest();
2912810SN/A
2928833Sdam.sunwoo@arm.com    // responses are never express snoops
2932810SN/A    assert(!pkt->isExpressSnoop());
2944871SN/A
2958833Sdam.sunwoo@arm.com    calcPacketTiming(pkt);
2968833Sdam.sunwoo@arm.com    Tick packetFinishTime = pkt->busLastWordDelay + curTick();
2978833Sdam.sunwoo@arm.com
2982810SN/A    // determine if the response is from a snoop request we
2992810SN/A    // created as the result of a normal request (in which case it
3004022SN/A    // should be in the outstandingReq), or if we merely forwarded
3014022SN/A    // someone else's snoop request
3024022SN/A    if (outstandingReq.find(pkt->req) == outstandingReq.end()) {
3032810SN/A        // this is a snoop response to a snoop request we
3042810SN/A        // forwarded, e.g. coming from the L1 and going to the L2
3052810SN/A        // this should be forwarded as a snoop response
3062810SN/A        bool success M5_VAR_USED = masterPorts[dest]->sendTimingSnoopResp(pkt);
3072810SN/A        assert(success);
3082810SN/A    } else {
3098833Sdam.sunwoo@arm.com        // we got a snoop response on one of our slave ports,
3102810SN/A        // i.e. from a coherent master connected to the bus, and
3118833Sdam.sunwoo@arm.com        // since we created the snoop request as part of
3128833Sdam.sunwoo@arm.com        // recvTiming, this should now be a normal response again
3138833Sdam.sunwoo@arm.com        outstandingReq.erase(pkt->req);
3142810SN/A
3152810SN/A        // this is a snoop response from a coherent master, with a
3162810SN/A        // destination field set on its way through the bus as
3172810SN/A        // request, hence it should never go back to where the
3182810SN/A        // snoop response came from, but instead to where the
3198833Sdam.sunwoo@arm.com        // original request came from
3202810SN/A        assert(slave_port_id != dest);
3212810SN/A
3228833Sdam.sunwoo@arm.com        // as a normal response, it should go back to a master
3238833Sdam.sunwoo@arm.com        // through one of our slave ports
3248833Sdam.sunwoo@arm.com        bool success M5_VAR_USED = slavePorts[dest]->sendTimingResp(pkt);
3252810SN/A
3262810SN/A        // currently it is illegal to block responses... can lead
3272810SN/A        // to deadlock
3282810SN/A        assert(success);
3298833Sdam.sunwoo@arm.com    }
3302810SN/A
3312810SN/A    snoopRespLayer.succeededTiming(packetFinishTime);
3328833Sdam.sunwoo@arm.com
3338833Sdam.sunwoo@arm.com    return true;
3348833Sdam.sunwoo@arm.com}
3352810SN/A
3362810SN/A
3374022SN/Avoid
3384022SN/ACoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id)
3394022SN/A{
3402810SN/A    // snoops should only happen if the system isn't bypassing caches
3412810SN/A    assert(!system->bypassCaches());
3422810SN/A
3432810SN/A    for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
3442810SN/A        SlavePort *p = *s;
3452810SN/A        // we could have gotten this request from a snooping master
3468833Sdam.sunwoo@arm.com        // (corresponding to our own slave port that is also in
3472810SN/A        // snoopPorts) and should not send it back to where it came
3488833Sdam.sunwoo@arm.com        // from
3498833Sdam.sunwoo@arm.com        if (exclude_slave_port_id == InvalidPortID ||
3508833Sdam.sunwoo@arm.com            p->getId() != exclude_slave_port_id) {
3512810SN/A            // cache is not allowed to refuse snoop
3522810SN/A            p->sendTimingSnoopReq(pkt);
3532810SN/A        }
3542810SN/A    }
3552810SN/A}
3568833Sdam.sunwoo@arm.com
3572810SN/Avoid
3582810SN/ACoherentBus::recvRetry(PortID master_port_id)
3598833Sdam.sunwoo@arm.com{
3608833Sdam.sunwoo@arm.com    // responses and snoop responses never block on forwarding them,
3618833Sdam.sunwoo@arm.com    // so the retry will always be coming from a port to which we
3622810SN/A    // tried to forward a request
3632810SN/A    reqLayer.recvRetry(master_port_id);
3642810SN/A}
3652810SN/A
3668833Sdam.sunwoo@arm.comTick
3672810SN/ACoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id)
3682810SN/A{
3698833Sdam.sunwoo@arm.com    DPRINTF(CoherentBus, "recvAtomic: packet src %s addr 0x%x cmd %s\n",
3708833Sdam.sunwoo@arm.com            slavePorts[slave_port_id]->name(), pkt->getAddr(),
3718833Sdam.sunwoo@arm.com            pkt->cmdString());
3722810SN/A
3732810SN/A    MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
3744022SN/A    Tick snoop_response_latency = 0;
3754022SN/A
3764022SN/A    // uncacheable requests need never be snooped
3772810SN/A    if (!pkt->req->isUncacheable() && !system->bypassCaches()) {
3782810SN/A        // forward to all snoopers but the source
3792810SN/A        std::pair<MemCmd, Tick> snoop_result =
3802810SN/A            forwardAtomic(pkt, slave_port_id);
3812810SN/A        snoop_response_cmd = snoop_result.first;
3822810SN/A        snoop_response_latency = snoop_result.second;
3832810SN/A    }
3842810SN/A
3858833Sdam.sunwoo@arm.com    // even if we had a snoop response, we must continue and also
3868833Sdam.sunwoo@arm.com    // perform the actual request at the destination
3878833Sdam.sunwoo@arm.com    PortID dest_id = findPort(pkt->getAddr());
3888833Sdam.sunwoo@arm.com
3892810SN/A    // forward the request to the appropriate destination
3902810SN/A    Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt);
3912810SN/A
3922810SN/A    // if we got a response from a snooper, restore it here
3932810SN/A    if (snoop_response_cmd != MemCmd::InvalidCmd) {
3948833Sdam.sunwoo@arm.com        // no one else should have responded
3952810SN/A        assert(!pkt->isResponse());
3962810SN/A        pkt->cmd = snoop_response_cmd;
3978833Sdam.sunwoo@arm.com        response_latency = snoop_response_latency;
3988833Sdam.sunwoo@arm.com    }
3998833Sdam.sunwoo@arm.com
4002810SN/A    // @todo: Not setting first-word time
4012810SN/A    pkt->busLastWordDelay = response_latency;
4022810SN/A    return response_latency;
4032810SN/A}
4048833Sdam.sunwoo@arm.com
4052810SN/ATick
4062810SN/ACoherentBus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id)
4078833Sdam.sunwoo@arm.com{
4088833Sdam.sunwoo@arm.com    DPRINTF(CoherentBus, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n",
4098833Sdam.sunwoo@arm.com            masterPorts[master_port_id]->name(), pkt->getAddr(),
4102810SN/A            pkt->cmdString());
4112810SN/A
4122810SN/A    // forward to all snoopers
4132810SN/A    std::pair<MemCmd, Tick> snoop_result =
4142810SN/A        forwardAtomic(pkt, InvalidPortID);
4152810SN/A    MemCmd snoop_response_cmd = snoop_result.first;
4162810SN/A    Tick snoop_response_latency = snoop_result.second;
4172810SN/A
4182810SN/A    if (snoop_response_cmd != MemCmd::InvalidCmd)
4192810SN/A        pkt->cmd = snoop_response_cmd;
4202810SN/A
4212810SN/A    // @todo: Not setting first-word time
4222810SN/A    pkt->busLastWordDelay = snoop_response_latency;
4232810SN/A    return snoop_response_latency;
4242810SN/A}
4252810SN/A
4262810SN/Astd::pair<MemCmd, Tick>
4272810SN/ACoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id)
4282810SN/A{
4292810SN/A    // the packet may be changed on snoops, record the original
4302810SN/A    // command to enable us to restore it between snoops so that
4312810SN/A    // additional snoops can take place properly
4322810SN/A    MemCmd orig_cmd = pkt->cmd;
4332810SN/A    MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
4342810SN/A    Tick snoop_response_latency = 0;
4352810SN/A
4362810SN/A    // snoops should only happen if the system isn't bypassing caches
43711436SRekai.GonzalezAlberquilla@arm.com    assert(!system->bypassCaches());
43811436SRekai.GonzalezAlberquilla@arm.com
43911436SRekai.GonzalezAlberquilla@arm.com    for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
44011436SRekai.GonzalezAlberquilla@arm.com        SlavePort *p = *s;
44111436SRekai.GonzalezAlberquilla@arm.com        // we could have gotten this request from a snooping master
44211436SRekai.GonzalezAlberquilla@arm.com        // (corresponding to our own slave port that is also in
4434626SN/A        // snoopPorts) and should not send it back to where it came
4448833Sdam.sunwoo@arm.com        // from
4454626SN/A        if (exclude_slave_port_id == InvalidPortID ||
4464626SN/A            p->getId() != exclude_slave_port_id) {
4478833Sdam.sunwoo@arm.com            Tick latency = p->sendAtomicSnoop(pkt);
4484626SN/A            // in contrast to a functional access, we have to keep on
4498833Sdam.sunwoo@arm.com            // going as all snoopers must be updated even if we get a
4508833Sdam.sunwoo@arm.com            // response
4518833Sdam.sunwoo@arm.com            if (pkt->isResponse()) {
4524626SN/A                // response from snoop agent
4534626SN/A                assert(pkt->cmd != orig_cmd);
4544626SN/A                assert(pkt->memInhibitAsserted());
4554626SN/A                // should only happen once
4564626SN/A                assert(snoop_response_cmd == MemCmd::InvalidCmd);
4574626SN/A                // save response state
4584626SN/A                snoop_response_cmd = pkt->cmd;
4594626SN/A                snoop_response_latency = latency;
4608833Sdam.sunwoo@arm.com                // restore original packet state for remaining snoopers
4614626SN/A                pkt->cmd = orig_cmd;
4624626SN/A            }
4634626SN/A        }
4644626SN/A    }
4658833Sdam.sunwoo@arm.com
4668833Sdam.sunwoo@arm.com    // the packet is restored as part of the loop and any potential
4678833Sdam.sunwoo@arm.com    // snoop response is part of the returned pair
4684626SN/A    return std::make_pair(snoop_response_cmd, snoop_response_latency);
4694626SN/A}
4704626SN/A
4714626SN/Avoid
4724626SN/ACoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id)
4738833Sdam.sunwoo@arm.com{
4744626SN/A    if (!pkt->isPrint()) {
4754871SN/A        // don't do DPRINTFs on PrintReq as it clutters up the output
4768833Sdam.sunwoo@arm.com        DPRINTF(CoherentBus,
4778833Sdam.sunwoo@arm.com                "recvFunctional: packet src %s addr 0x%x cmd %s\n",
4788833Sdam.sunwoo@arm.com                slavePorts[slave_port_id]->name(), pkt->getAddr(),
4794626SN/A                pkt->cmdString());
4804626SN/A    }
4814626SN/A
4824626SN/A    // uncacheable requests need never be snooped
4838833Sdam.sunwoo@arm.com    if (!pkt->req->isUncacheable() && !system->bypassCaches()) {
4844626SN/A        // forward to all snoopers but the source
4854871SN/A        forwardFunctional(pkt, slave_port_id);
4868833Sdam.sunwoo@arm.com    }
4878833Sdam.sunwoo@arm.com
4888833Sdam.sunwoo@arm.com    // there is no need to continue if the snooping has found what we
4894626SN/A    // were looking for and the packet is already a response
4904626SN/A    if (!pkt->isResponse()) {
4914626SN/A        PortID dest_id = findPort(pkt->getAddr());
4924626SN/A
4934626SN/A        masterPorts[dest_id]->sendFunctional(pkt);
4944626SN/A    }
4954626SN/A}
4968833Sdam.sunwoo@arm.com
4974626SN/Avoid
4984626SN/ACoherentBus::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id)
4994626SN/A{
5004626SN/A    if (!pkt->isPrint()) {
5018833Sdam.sunwoo@arm.com        // don't do DPRINTFs on PrintReq as it clutters up the output
5028833Sdam.sunwoo@arm.com        DPRINTF(CoherentBus,
5038833Sdam.sunwoo@arm.com                "recvFunctionalSnoop: packet src %s addr 0x%x cmd %s\n",
5044626SN/A                masterPorts[master_port_id]->name(), pkt->getAddr(),
5054626SN/A                pkt->cmdString());
5064626SN/A    }
5074626SN/A
5084626SN/A    // forward to all snoopers
5098833Sdam.sunwoo@arm.com    forwardFunctional(pkt, InvalidPortID);
5104626SN/A}
5114871SN/A
5128833Sdam.sunwoo@arm.comvoid
5138833Sdam.sunwoo@arm.comCoherentBus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id)
5148833Sdam.sunwoo@arm.com{
5154626SN/A    // snoops should only happen if the system isn't bypassing caches
5164626SN/A    assert(!system->bypassCaches());
5174626SN/A
5184626SN/A    for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
5198833Sdam.sunwoo@arm.com        SlavePort *p = *s;
5204626SN/A        // we could have gotten this request from a snooping master
5214871SN/A        // (corresponding to our own slave port that is also in
5228833Sdam.sunwoo@arm.com        // snoopPorts) and should not send it back to where it came
5238833Sdam.sunwoo@arm.com        // from
5248833Sdam.sunwoo@arm.com        if (exclude_slave_port_id == InvalidPortID ||
5254626SN/A            p->getId() != exclude_slave_port_id)
5264626SN/A            p->sendFunctionalSnoop(pkt);
5274626SN/A
5284626SN/A        // if we get a response we are done
5294626SN/A        if (pkt->isResponse()) {
5304626SN/A            break;
5314626SN/A        }
5328833Sdam.sunwoo@arm.com    }
5334626SN/A}
5344626SN/A
5354626SN/Aunsigned int
5364626SN/ACoherentBus::drain(DrainManager *dm)
5378833Sdam.sunwoo@arm.com{
5388833Sdam.sunwoo@arm.com    // sum up the individual layers
5398833Sdam.sunwoo@arm.com    return reqLayer.drain(dm) + respLayer.drain(dm) + snoopRespLayer.drain(dm);
5404626SN/A}
5414626SN/A
5424626SN/ACoherentBus *
5434626SN/ACoherentBusParams::create()
5444626SN/A{
5458833Sdam.sunwoo@arm.com    return new CoherentBus(this);
5464626SN/A}
5474871SN/A