coherent_xbar.cc revision 9278
12381SN/A/*
210713Sandreas.hansson@arm.com * Copyright (c) 2011-2012 ARM Limited
38711Sandreas.hansson@arm.com * All rights reserved
48711Sandreas.hansson@arm.com *
58711Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall
68711Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual
78711Sandreas.hansson@arm.com * property including but not limited to intellectual property relating
88711Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software
98711Sandreas.hansson@arm.com * licensed hereunder.  You may use the software subject to the license
108711Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated
118711Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software,
128711Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form.
138711Sandreas.hansson@arm.com *
142381SN/A * Copyright (c) 2006 The Regents of The University of Michigan
152381SN/A * All rights reserved.
162381SN/A *
172381SN/A * Redistribution and use in source and binary forms, with or without
182381SN/A * modification, are permitted provided that the following conditions are
192381SN/A * met: redistributions of source code must retain the above copyright
202381SN/A * notice, this list of conditions and the following disclaimer;
212381SN/A * redistributions in binary form must reproduce the above copyright
222381SN/A * notice, this list of conditions and the following disclaimer in the
232381SN/A * documentation and/or other materials provided with the distribution;
242381SN/A * neither the name of the copyright holders nor the names of its
252381SN/A * contributors may be used to endorse or promote products derived from
262381SN/A * this software without specific prior written permission.
272381SN/A *
282381SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
292381SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
302381SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
312381SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
322381SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
332381SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
342381SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
352381SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
362381SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
372381SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382381SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392665Ssaidi@eecs.umich.edu *
402665Ssaidi@eecs.umich.edu * Authors: Ali Saidi
418853Sandreas.hansson@arm.com *          Andreas Hansson
428922Swilliam.wang@arm.com *          William Wang
432381SN/A */
442381SN/A
452381SN/A/**
462381SN/A * @file
478922Swilliam.wang@arm.com * Definition of a bus object.
482381SN/A */
492381SN/A
502381SN/A#include "base/misc.hh"
512381SN/A#include "base/trace.hh"
522381SN/A#include "debug/BusAddrRanges.hh"
539235Sandreas.hansson@arm.com#include "debug/CoherentBus.hh"
542381SN/A#include "mem/coherent_bus.hh"
552381SN/A
563401Sktlim@umich.eduCoherentBus::CoherentBus(const CoherentBusParams *p)
573401Sktlim@umich.edu    : BaseBus(p), reqLayer(*this, ".reqLayer", p->clock),
582381SN/A      respLayer(*this, ".respLayer", p->clock),
598922Swilliam.wang@arm.com      snoopRespLayer(*this, ".snoopRespLayer", p->clock)
608922Swilliam.wang@arm.com{
619087Sandreas.hansson@arm.com    // create the ports based on the size of the master and slave
622381SN/A    // vector ports, and the presence of the default port, the ports
638708Sandreas.hansson@arm.com    // are enumerated starting from zero
642381SN/A    for (int i = 0; i < p->port_master_connection_count; ++i) {
658922Swilliam.wang@arm.com        std::string portName = csprintf("%s.master[%d]", name(), i);
668922Swilliam.wang@arm.com        MasterPort* bp = new CoherentBusMasterPort(portName, *this, i);
678922Swilliam.wang@arm.com        masterPorts.push_back(bp);
688922Swilliam.wang@arm.com    }
698922Swilliam.wang@arm.com
708922Swilliam.wang@arm.com    // see if we have a default slave device connected and if so add
715476Snate@binkert.org    // our corresponding master port
722640Sstever@eecs.umich.edu    if (p->port_default_connection_count) {
738965Sandreas.hansson@arm.com        defaultPortID = masterPorts.size();
748965Sandreas.hansson@arm.com        std::string portName = name() + ".default";
759031Sandreas.hansson@arm.com        MasterPort* bp = new CoherentBusMasterPort(portName, *this,
768965Sandreas.hansson@arm.com                                                   defaultPortID);
779031Sandreas.hansson@arm.com        masterPorts.push_back(bp);
788965Sandreas.hansson@arm.com    }
798922Swilliam.wang@arm.com
808922Swilliam.wang@arm.com    // create the slave ports, once again starting at zero
818922Swilliam.wang@arm.com    for (int i = 0; i < p->port_slave_connection_count; ++i) {
828922Swilliam.wang@arm.com        std::string portName = csprintf("%s.slave[%d]", name(), i);
838922Swilliam.wang@arm.com        SlavePort* bp = new CoherentBusSlavePort(portName, *this, i);
848922Swilliam.wang@arm.com        slavePorts.push_back(bp);
858922Swilliam.wang@arm.com    }
868922Swilliam.wang@arm.com
878965Sandreas.hansson@arm.com    clearPortCache();
888922Swilliam.wang@arm.com}
899031Sandreas.hansson@arm.com
908922Swilliam.wang@arm.comvoid
918922Swilliam.wang@arm.comCoherentBus::init()
928922Swilliam.wang@arm.com{
938922Swilliam.wang@arm.com    // the base class is responsible for determining the block size
948922Swilliam.wang@arm.com    BaseBus::init();
953401Sktlim@umich.edu
962381SN/A    // iterate over our slave ports and determine which of our
972640Sstever@eecs.umich.edu    // neighbouring master ports are snooping and add them as snoopers
982640Sstever@eecs.umich.edu    for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end();
998922Swilliam.wang@arm.com         ++p) {
1004190Ssaidi@eecs.umich.edu        // check if the connected master port is snooping
1018965Sandreas.hansson@arm.com        if ((*p)->isSnooping()) {
1029031Sandreas.hansson@arm.com            DPRINTF(BusAddrRanges, "Adding snooping master %s\n",
1038965Sandreas.hansson@arm.com                    (*p)->getMasterPort().name());
1048922Swilliam.wang@arm.com            snoopPorts.push_back(*p);
1058922Swilliam.wang@arm.com        }
1068922Swilliam.wang@arm.com    }
1079294Sandreas.hansson@arm.com
1089294Sandreas.hansson@arm.com    if (snoopPorts.empty())
1099294Sandreas.hansson@arm.com        warn("CoherentBus %s has no snooping ports attached!\n", name());
1109294Sandreas.hansson@arm.com}
1119294Sandreas.hansson@arm.com
1129294Sandreas.hansson@arm.combool
1139294Sandreas.hansson@arm.comCoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
1149294Sandreas.hansson@arm.com{
1159294Sandreas.hansson@arm.com    // determine the source port based on the id
1169294Sandreas.hansson@arm.com    SlavePort *src_port = slavePorts[slave_port_id];
1179294Sandreas.hansson@arm.com
1189294Sandreas.hansson@arm.com    // remember if the packet is an express snoop
1199294Sandreas.hansson@arm.com    bool is_express_snoop = pkt->isExpressSnoop();
1209294Sandreas.hansson@arm.com
1219294Sandreas.hansson@arm.com    // test if the bus should be considered occupied for the current
1229294Sandreas.hansson@arm.com    // port, and exclude express snoops from the check
1239294Sandreas.hansson@arm.com    if (!is_express_snoop && !reqLayer.tryTiming(src_port)) {
1249294Sandreas.hansson@arm.com        DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x BUSY\n",
1259294Sandreas.hansson@arm.com                src_port->name(), pkt->cmdString(), pkt->getAddr());
1269294Sandreas.hansson@arm.com        return false;
1279294Sandreas.hansson@arm.com    }
1289294Sandreas.hansson@arm.com
1299294Sandreas.hansson@arm.com    DPRINTF(CoherentBus, "recvTimingReq: src %s %s expr %d 0x%x\n",
1309294Sandreas.hansson@arm.com            src_port->name(), pkt->cmdString(), is_express_snoop,
1319294Sandreas.hansson@arm.com            pkt->getAddr());
1329294Sandreas.hansson@arm.com
1339294Sandreas.hansson@arm.com    // set the source port for routing of the response
1349294Sandreas.hansson@arm.com    pkt->setSrc(slave_port_id);
1359294Sandreas.hansson@arm.com
1369294Sandreas.hansson@arm.com    Tick headerFinishTime = is_express_snoop ? 0 : calcPacketTiming(pkt);
1379294Sandreas.hansson@arm.com    Tick packetFinishTime = is_express_snoop ? 0 : pkt->finishTime;
1389294Sandreas.hansson@arm.com
1399294Sandreas.hansson@arm.com    // uncacheable requests need never be snooped
1409294Sandreas.hansson@arm.com    if (!pkt->req->isUncacheable()) {
1419294Sandreas.hansson@arm.com        // the packet is a memory-mapped request and should be
1429294Sandreas.hansson@arm.com        // broadcasted to our snoopers but the source
1439294Sandreas.hansson@arm.com        forwardTiming(pkt, slave_port_id);
1449294Sandreas.hansson@arm.com    }
1459294Sandreas.hansson@arm.com
1469294Sandreas.hansson@arm.com    // remember if we add an outstanding req so we can undo it if
1479294Sandreas.hansson@arm.com    // necessary, if the packet needs a response, we should add it
1489294Sandreas.hansson@arm.com    // as outstanding and express snoops never fail so there is
1499294Sandreas.hansson@arm.com    // not need to worry about them
1509294Sandreas.hansson@arm.com    bool add_outstanding = !is_express_snoop && pkt->needsResponse();
1519294Sandreas.hansson@arm.com
1529294Sandreas.hansson@arm.com    // keep track that we have an outstanding request packet
1539294Sandreas.hansson@arm.com    // matching this request, this is used by the coherency
1549294Sandreas.hansson@arm.com    // mechanism in determining what to do with snoop responses
1559294Sandreas.hansson@arm.com    // (in recvTimingSnoop)
1569294Sandreas.hansson@arm.com    if (add_outstanding) {
1579294Sandreas.hansson@arm.com        // we should never have an exsiting request outstanding
1588922Swilliam.wang@arm.com        assert(outstandingReq.find(pkt->req) == outstandingReq.end());
1598922Swilliam.wang@arm.com        outstandingReq.insert(pkt->req);
1608922Swilliam.wang@arm.com    }
1619294Sandreas.hansson@arm.com
1629294Sandreas.hansson@arm.com    // since it is a normal request, determine the destination
1639294Sandreas.hansson@arm.com    // based on the address and attempt to send the packet
1649294Sandreas.hansson@arm.com    bool success = masterPorts[findPort(pkt->getAddr())]->sendTimingReq(pkt);
1659294Sandreas.hansson@arm.com
1668922Swilliam.wang@arm.com    // if this is an express snoop, we are done at this point
1679294Sandreas.hansson@arm.com    if (is_express_snoop) {
1688922Swilliam.wang@arm.com        assert(success);
1698922Swilliam.wang@arm.com    } else {
1708975Sandreas.hansson@arm.com        // for normal requests, check if successful
1718975Sandreas.hansson@arm.com        if (!success)  {
1728922Swilliam.wang@arm.com            // inhibited packets should never be forced to retry
1738922Swilliam.wang@arm.com            assert(!pkt->memInhibitAsserted());
1748922Swilliam.wang@arm.com
1758922Swilliam.wang@arm.com            // if it was added as outstanding and the send failed, then
1768922Swilliam.wang@arm.com            // erase it again
1778922Swilliam.wang@arm.com            if (add_outstanding)
1788965Sandreas.hansson@arm.com                outstandingReq.erase(pkt->req);
1799031Sandreas.hansson@arm.com
1808922Swilliam.wang@arm.com            DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n",
1818922Swilliam.wang@arm.com                    src_port->name(), pkt->cmdString(), pkt->getAddr());
1829178Sandreas.hansson@arm.com
1839178Sandreas.hansson@arm.com            // update the bus state and schedule an idle event
1849178Sandreas.hansson@arm.com            reqLayer.failedTiming(src_port, headerFinishTime);
1859178Sandreas.hansson@arm.com        } else {
1869294Sandreas.hansson@arm.com            // update the bus state and schedule an idle event
1879178Sandreas.hansson@arm.com            reqLayer.succeededTiming(packetFinishTime);
1889178Sandreas.hansson@arm.com        }
1899178Sandreas.hansson@arm.com    }
1909178Sandreas.hansson@arm.com
1919178Sandreas.hansson@arm.com    return success;
1929178Sandreas.hansson@arm.com}
1938922Swilliam.wang@arm.com
1948948Sandreas.hansson@arm.combool
1958948Sandreas.hansson@arm.comCoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id)
1968948Sandreas.hansson@arm.com{
1978948Sandreas.hansson@arm.com    // determine the source port based on the id
1988948Sandreas.hansson@arm.com    MasterPort *src_port = masterPorts[master_port_id];
1998948Sandreas.hansson@arm.com
2008948Sandreas.hansson@arm.com    // test if the bus should be considered occupied for the current
2018948Sandreas.hansson@arm.com    // port
2028948Sandreas.hansson@arm.com    if (!respLayer.tryTiming(src_port)) {
2038948Sandreas.hansson@arm.com        DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n",
2048948Sandreas.hansson@arm.com                src_port->name(), pkt->cmdString(), pkt->getAddr());
2058948Sandreas.hansson@arm.com        return false;
2068948Sandreas.hansson@arm.com    }
2078948Sandreas.hansson@arm.com
2088948Sandreas.hansson@arm.com    DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x\n",
2098948Sandreas.hansson@arm.com            src_port->name(), pkt->cmdString(), pkt->getAddr());
2108948Sandreas.hansson@arm.com
2118948Sandreas.hansson@arm.com    calcPacketTiming(pkt);
2128948Sandreas.hansson@arm.com    Tick packetFinishTime = pkt->finishTime;
2138948Sandreas.hansson@arm.com
2148975Sandreas.hansson@arm.com    // the packet is a normal response to a request that we should
2158975Sandreas.hansson@arm.com    // have seen passing through the bus
2168975Sandreas.hansson@arm.com    assert(outstandingReq.find(pkt->req) != outstandingReq.end());
21710713Sandreas.hansson@arm.com
2188975Sandreas.hansson@arm.com    // remove it as outstanding
2198975Sandreas.hansson@arm.com    outstandingReq.erase(pkt->req);
2208975Sandreas.hansson@arm.com
2218975Sandreas.hansson@arm.com    // send the packet to the destination through one of our slave
2228975Sandreas.hansson@arm.com    // ports, as determined by the destination field
2238975Sandreas.hansson@arm.com    bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTimingResp(pkt);
2248975Sandreas.hansson@arm.com
2258948Sandreas.hansson@arm.com    // currently it is illegal to block responses... can lead to
2268948Sandreas.hansson@arm.com    // deadlock
2278975Sandreas.hansson@arm.com    assert(success);
2288975Sandreas.hansson@arm.com
2298975Sandreas.hansson@arm.com    respLayer.succeededTiming(packetFinishTime);
23010713Sandreas.hansson@arm.com
23110713Sandreas.hansson@arm.com    return true;
2328975Sandreas.hansson@arm.com}
2338975Sandreas.hansson@arm.com
2348948Sandreas.hansson@arm.comvoid
2358975Sandreas.hansson@arm.comCoherentBus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id)
2368922Swilliam.wang@arm.com{
2378922Swilliam.wang@arm.com    DPRINTF(CoherentBus, "recvTimingSnoopReq: src %s %s 0x%x\n",
2389087Sandreas.hansson@arm.com            masterPorts[master_port_id]->name(), pkt->cmdString(),
23910713Sandreas.hansson@arm.com            pkt->getAddr());
24010713Sandreas.hansson@arm.com
24110713Sandreas.hansson@arm.com    // we should only see express snoops from caches
2429087Sandreas.hansson@arm.com    assert(pkt->isExpressSnoop());
24310713Sandreas.hansson@arm.com
2449087Sandreas.hansson@arm.com    // set the source port for routing of the response
2459087Sandreas.hansson@arm.com    pkt->setSrc(master_port_id);
2468922Swilliam.wang@arm.com
2478711Sandreas.hansson@arm.com    // forward to all snoopers
2488922Swilliam.wang@arm.com    forwardTiming(pkt, InvalidPortID);
2498922Swilliam.wang@arm.com
2508922Swilliam.wang@arm.com    // a snoop request came from a connected slave device (one of
2518711Sandreas.hansson@arm.com    // our master ports), and if it is not coming from the slave
2528711Sandreas.hansson@arm.com    // device responsible for the address range something is
2538711Sandreas.hansson@arm.com    // wrong, hence there is nothing further to do as the packet
2548922Swilliam.wang@arm.com    // would be going back to where it came from
2552381SN/A    assert(master_port_id == findPort(pkt->getAddr()));
2568711Sandreas.hansson@arm.com}
2579089Sandreas.hansson@arm.com
2589089Sandreas.hansson@arm.combool
2599089Sandreas.hansson@arm.comCoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id)
2609089Sandreas.hansson@arm.com{
2615314Sstever@gmail.com    // determine the source port based on the id
2625314Sstever@gmail.com    SlavePort* src_port = slavePorts[slave_port_id];
2635314Sstever@gmail.com
2645314Sstever@gmail.com    // test if the bus should be considered occupied for the current
2658975Sandreas.hansson@arm.com    // port
2668975Sandreas.hansson@arm.com    if (!snoopRespLayer.tryTiming(src_port)) {
2678975Sandreas.hansson@arm.com        DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n",
2688975Sandreas.hansson@arm.com                src_port->name(), pkt->cmdString(), pkt->getAddr());
2698975Sandreas.hansson@arm.com        return false;
2708975Sandreas.hansson@arm.com    }
2718975Sandreas.hansson@arm.com
2728975Sandreas.hansson@arm.com    DPRINTF(CoherentBus, "recvTimingSnoop: src %s %s 0x%x\n",
2738975Sandreas.hansson@arm.com            src_port->name(), pkt->cmdString(), pkt->getAddr());
2748975Sandreas.hansson@arm.com
2758975Sandreas.hansson@arm.com    // get the destination from the packet
2768975Sandreas.hansson@arm.com    PortID dest = pkt->getDest();
2778975Sandreas.hansson@arm.com
2788975Sandreas.hansson@arm.com    // responses are never express snoops
2798975Sandreas.hansson@arm.com    assert(!pkt->isExpressSnoop());
2808975Sandreas.hansson@arm.com
2818975Sandreas.hansson@arm.com    calcPacketTiming(pkt);
2828975Sandreas.hansson@arm.com    Tick packetFinishTime = pkt->finishTime;
2838975Sandreas.hansson@arm.com
2848975Sandreas.hansson@arm.com    // determine if the response is from a snoop request we
2858975Sandreas.hansson@arm.com    // created as the result of a normal request (in which case it
2868975Sandreas.hansson@arm.com    // should be in the outstandingReq), or if we merely forwarded
2878975Sandreas.hansson@arm.com    // someone else's snoop request
2888975Sandreas.hansson@arm.com    if (outstandingReq.find(pkt->req) == outstandingReq.end()) {
2898975Sandreas.hansson@arm.com        // this is a snoop response to a snoop request we
2908975Sandreas.hansson@arm.com        // forwarded, e.g. coming from the L1 and going to the L2
2918975Sandreas.hansson@arm.com        // this should be forwarded as a snoop response
2928975Sandreas.hansson@arm.com        bool success M5_VAR_USED = masterPorts[dest]->sendTimingSnoopResp(pkt);
2938975Sandreas.hansson@arm.com        assert(success);
2948975Sandreas.hansson@arm.com    } else {
2958975Sandreas.hansson@arm.com        // we got a snoop response on one of our slave ports,
2968975Sandreas.hansson@arm.com        // i.e. from a coherent master connected to the bus, and
2978975Sandreas.hansson@arm.com        // since we created the snoop request as part of
2988975Sandreas.hansson@arm.com        // recvTiming, this should now be a normal response again
29910713Sandreas.hansson@arm.com        outstandingReq.erase(pkt->req);
30010713Sandreas.hansson@arm.com
30110713Sandreas.hansson@arm.com        // this is a snoop response from a coherent master, with a
3029087Sandreas.hansson@arm.com        // destination field set on its way through the bus as
30310713Sandreas.hansson@arm.com        // request, hence it should never go back to where the
30410713Sandreas.hansson@arm.com        // snoop response came from, but instead to where the
30510713Sandreas.hansson@arm.com        // original request came from
30610713Sandreas.hansson@arm.com        assert(slave_port_id != dest);
30710713Sandreas.hansson@arm.com
30810713Sandreas.hansson@arm.com        // as a normal response, it should go back to a master
30910713Sandreas.hansson@arm.com        // through one of our slave ports
31010713Sandreas.hansson@arm.com        bool success M5_VAR_USED = slavePorts[dest]->sendTimingResp(pkt);
31110713Sandreas.hansson@arm.com
31210713Sandreas.hansson@arm.com        // currently it is illegal to block responses... can lead
31310713Sandreas.hansson@arm.com        // to deadlock
3149087Sandreas.hansson@arm.com        assert(success);
3159087Sandreas.hansson@arm.com    }
3168975Sandreas.hansson@arm.com
3179325Sandreas.hansson@arm.com    snoopRespLayer.succeededTiming(packetFinishTime);
3188975Sandreas.hansson@arm.com
3199325Sandreas.hansson@arm.com    return true;
3208975Sandreas.hansson@arm.com}
3218975Sandreas.hansson@arm.com
3228975Sandreas.hansson@arm.com
3232381SN/Avoid
3242381SN/ACoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id)
3258922Swilliam.wang@arm.com{
3268922Swilliam.wang@arm.com    for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
3278922Swilliam.wang@arm.com        SlavePort *p = *s;
3288922Swilliam.wang@arm.com        // we could have gotten this request from a snooping master
3298922Swilliam.wang@arm.com        // (corresponding to our own slave port that is also in
3308922Swilliam.wang@arm.com        // snoopPorts) and should not send it back to where it came
3319294Sandreas.hansson@arm.com        // from
3328922Swilliam.wang@arm.com        if (exclude_slave_port_id == InvalidPortID ||
3338922Swilliam.wang@arm.com            p->getId() != exclude_slave_port_id) {
3348975Sandreas.hansson@arm.com            // cache is not allowed to refuse snoop
3358975Sandreas.hansson@arm.com            p->sendTimingSnoopReq(pkt);
3368922Swilliam.wang@arm.com        }
3378922Swilliam.wang@arm.com    }
3388922Swilliam.wang@arm.com}
3398922Swilliam.wang@arm.com
3408922Swilliam.wang@arm.comvoid
3418922Swilliam.wang@arm.comCoherentBus::recvRetry()
3428965Sandreas.hansson@arm.com{
3439031Sandreas.hansson@arm.com    // responses and snoop responses never block on forwarding them,
3448922Swilliam.wang@arm.com    // so the retry will always be coming from a port to which we
3458922Swilliam.wang@arm.com    // tried to forward a request
3468922Swilliam.wang@arm.com    reqLayer.recvRetry();
3478948Sandreas.hansson@arm.com}
3488948Sandreas.hansson@arm.com
3498948Sandreas.hansson@arm.comTick
3508948Sandreas.hansson@arm.comCoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id)
3518948Sandreas.hansson@arm.com{
3528948Sandreas.hansson@arm.com    DPRINTF(CoherentBus, "recvAtomic: packet src %s addr 0x%x cmd %s\n",
3538948Sandreas.hansson@arm.com            slavePorts[slave_port_id]->name(), pkt->getAddr(),
3548948Sandreas.hansson@arm.com            pkt->cmdString());
3558948Sandreas.hansson@arm.com
3568948Sandreas.hansson@arm.com    MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
3578948Sandreas.hansson@arm.com    Tick snoop_response_latency = 0;
3588948Sandreas.hansson@arm.com
3598948Sandreas.hansson@arm.com    // uncacheable requests need never be snooped
3608948Sandreas.hansson@arm.com    if (!pkt->req->isUncacheable()) {
3618948Sandreas.hansson@arm.com        // forward to all snoopers but the source
3628948Sandreas.hansson@arm.com        std::pair<MemCmd, Tick> snoop_result =
3638948Sandreas.hansson@arm.com            forwardAtomic(pkt, slave_port_id);
3648948Sandreas.hansson@arm.com        snoop_response_cmd = snoop_result.first;
3658948Sandreas.hansson@arm.com        snoop_response_latency = snoop_result.second;
3668948Sandreas.hansson@arm.com    }
3678975Sandreas.hansson@arm.com
3688975Sandreas.hansson@arm.com    // even if we had a snoop response, we must continue and also
3698975Sandreas.hansson@arm.com    // perform the actual request at the destination
37010713Sandreas.hansson@arm.com    PortID dest_id = findPort(pkt->getAddr());
3718975Sandreas.hansson@arm.com
3728975Sandreas.hansson@arm.com    // forward the request to the appropriate destination
3738975Sandreas.hansson@arm.com    Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt);
3748975Sandreas.hansson@arm.com
3758975Sandreas.hansson@arm.com    // if we got a response from a snooper, restore it here
3768975Sandreas.hansson@arm.com    if (snoop_response_cmd != MemCmd::InvalidCmd) {
3778975Sandreas.hansson@arm.com        // no one else should have responded
3788948Sandreas.hansson@arm.com        assert(!pkt->isResponse());
3798948Sandreas.hansson@arm.com        pkt->cmd = snoop_response_cmd;
3808975Sandreas.hansson@arm.com        response_latency = snoop_response_latency;
3818975Sandreas.hansson@arm.com    }
3828975Sandreas.hansson@arm.com
3838975Sandreas.hansson@arm.com    pkt->finishTime = curTick() + response_latency;
3848975Sandreas.hansson@arm.com    return response_latency;
3858948Sandreas.hansson@arm.com}
3868975Sandreas.hansson@arm.com
3878948Sandreas.hansson@arm.comTick
3888948Sandreas.hansson@arm.comCoherentBus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id)
3899087Sandreas.hansson@arm.com{
39010713Sandreas.hansson@arm.com    DPRINTF(CoherentBus, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n",
3919087Sandreas.hansson@arm.com            masterPorts[master_port_id]->name(), pkt->getAddr(),
39210713Sandreas.hansson@arm.com            pkt->cmdString());
39310713Sandreas.hansson@arm.com
39410713Sandreas.hansson@arm.com    // forward to all snoopers
39510713Sandreas.hansson@arm.com    std::pair<MemCmd, Tick> snoop_result =
39610713Sandreas.hansson@arm.com        forwardAtomic(pkt, InvalidPortID);
39710713Sandreas.hansson@arm.com    MemCmd snoop_response_cmd = snoop_result.first;
39810713Sandreas.hansson@arm.com    Tick snoop_response_latency = snoop_result.second;
3999087Sandreas.hansson@arm.com
4009087Sandreas.hansson@arm.com    if (snoop_response_cmd != MemCmd::InvalidCmd)
4019088Sandreas.hansson@arm.com        pkt->cmd = snoop_response_cmd;
4029088Sandreas.hansson@arm.com
4039088Sandreas.hansson@arm.com    pkt->finishTime = curTick() + snoop_response_latency;
4049088Sandreas.hansson@arm.com    return snoop_response_latency;
4059088Sandreas.hansson@arm.com}
4069088Sandreas.hansson@arm.com
4079088Sandreas.hansson@arm.comstd::pair<MemCmd, Tick>
4088922Swilliam.wang@arm.comCoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id)
4098922Swilliam.wang@arm.com{
41010413SCurtis.Dunham@arm.com    // the packet may be changed on snoops, record the original
41110413SCurtis.Dunham@arm.com    // command to enable us to restore it between snoops so that
41210413SCurtis.Dunham@arm.com    // additional snoops can take place properly
41310413SCurtis.Dunham@arm.com    MemCmd orig_cmd = pkt->cmd;
41410413SCurtis.Dunham@arm.com    MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
4158922Swilliam.wang@arm.com    Tick snoop_response_latency = 0;
4168922Swilliam.wang@arm.com
4178922Swilliam.wang@arm.com    for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
4188922Swilliam.wang@arm.com        SlavePort *p = *s;
4198922Swilliam.wang@arm.com        // we could have gotten this request from a snooping master
4208922Swilliam.wang@arm.com        // (corresponding to our own slave port that is also in
4218922Swilliam.wang@arm.com        // snoopPorts) and should not send it back to where it came
4228922Swilliam.wang@arm.com        // from
4239090Sandreas.hansson@arm.com        if (exclude_slave_port_id == InvalidPortID ||
4248975Sandreas.hansson@arm.com            p->getId() != exclude_slave_port_id) {
4258975Sandreas.hansson@arm.com            Tick latency = p->sendAtomicSnoop(pkt);
4268975Sandreas.hansson@arm.com            // in contrast to a functional access, we have to keep on
4278975Sandreas.hansson@arm.com            // going as all snoopers must be updated even if we get a
4289178Sandreas.hansson@arm.com            // response
4299178Sandreas.hansson@arm.com            if (pkt->isResponse()) {
4309178Sandreas.hansson@arm.com                // response from snoop agent
4319178Sandreas.hansson@arm.com                assert(pkt->cmd != orig_cmd);
4329178Sandreas.hansson@arm.com                assert(pkt->memInhibitAsserted());
4339178Sandreas.hansson@arm.com                // should only happen once
4349178Sandreas.hansson@arm.com                assert(snoop_response_cmd == MemCmd::InvalidCmd);
4359178Sandreas.hansson@arm.com                // save response state
4369178Sandreas.hansson@arm.com                snoop_response_cmd = pkt->cmd;
4379178Sandreas.hansson@arm.com                snoop_response_latency = latency;
4389178Sandreas.hansson@arm.com                // restore original packet state for remaining snoopers
4399178Sandreas.hansson@arm.com                pkt->cmd = orig_cmd;
4408975Sandreas.hansson@arm.com            }
4418975Sandreas.hansson@arm.com        }
4428975Sandreas.hansson@arm.com    }
4438975Sandreas.hansson@arm.com
4448975Sandreas.hansson@arm.com    // the packet is restored as part of the loop and any potential
4458975Sandreas.hansson@arm.com    // snoop response is part of the returned pair
4468975Sandreas.hansson@arm.com    return std::make_pair(snoop_response_cmd, snoop_response_latency);
4478975Sandreas.hansson@arm.com}
4488975Sandreas.hansson@arm.com
4498975Sandreas.hansson@arm.comvoid
4508975Sandreas.hansson@arm.comCoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id)
4518975Sandreas.hansson@arm.com{
4528975Sandreas.hansson@arm.com    if (!pkt->isPrint()) {
4538975Sandreas.hansson@arm.com        // don't do DPRINTFs on PrintReq as it clutters up the output
4548975Sandreas.hansson@arm.com        DPRINTF(CoherentBus,
4558975Sandreas.hansson@arm.com                "recvFunctional: packet src %s addr 0x%x cmd %s\n",
4568975Sandreas.hansson@arm.com                slavePorts[slave_port_id]->name(), pkt->getAddr(),
4578975Sandreas.hansson@arm.com                pkt->cmdString());
4588975Sandreas.hansson@arm.com    }
4598975Sandreas.hansson@arm.com
4608975Sandreas.hansson@arm.com    // uncacheable requests need never be snooped
4618975Sandreas.hansson@arm.com    if (!pkt->req->isUncacheable()) {
4629087Sandreas.hansson@arm.com        // forward to all snoopers but the source
4639087Sandreas.hansson@arm.com        forwardFunctional(pkt, slave_port_id);
4649087Sandreas.hansson@arm.com    }
4659087Sandreas.hansson@arm.com
4669087Sandreas.hansson@arm.com    // there is no need to continue if the snooping has found what we
46710713Sandreas.hansson@arm.com    // were looking for and the packet is already a response
4689087Sandreas.hansson@arm.com    if (!pkt->isResponse()) {
4698922Swilliam.wang@arm.com        PortID dest_id = findPort(pkt->getAddr());
4708922Swilliam.wang@arm.com
4712381SN/A        masterPorts[dest_id]->sendFunctional(pkt);
472    }
473}
474
475void
476CoherentBus::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id)
477{
478    if (!pkt->isPrint()) {
479        // don't do DPRINTFs on PrintReq as it clutters up the output
480        DPRINTF(CoherentBus,
481                "recvFunctionalSnoop: packet src %s addr 0x%x cmd %s\n",
482                masterPorts[master_port_id]->name(), pkt->getAddr(),
483                pkt->cmdString());
484    }
485
486    // forward to all snoopers
487    forwardFunctional(pkt, InvalidPortID);
488}
489
490void
491CoherentBus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id)
492{
493    for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
494        SlavePort *p = *s;
495        // we could have gotten this request from a snooping master
496        // (corresponding to our own slave port that is also in
497        // snoopPorts) and should not send it back to where it came
498        // from
499        if (exclude_slave_port_id == InvalidPortID ||
500            p->getId() != exclude_slave_port_id)
501            p->sendFunctionalSnoop(pkt);
502
503        // if we get a response we are done
504        if (pkt->isResponse()) {
505            break;
506        }
507    }
508}
509
510unsigned int
511CoherentBus::drain(Event *de)
512{
513    // sum up the individual layers
514    return reqLayer.drain(de) + respLayer.drain(de) + snoopRespLayer.drain(de);
515}
516
517CoherentBus *
518CoherentBusParams::create()
519{
520    return new CoherentBus(this);
521}
522